アップルが提供するビデオチュートリアルを見てみると、プロトコル指向のプログラミングラングとリンゴは、プログラマがクラスよりもプロトコルを使用するよう促しているようです。 私の個人的見解では、プロトコルに明らかな利点はないと思う。クラスはプロトコルに準拠することができますが、スーパークラスから継承することもできます。プロトコルに拡張を追加できますが、クラスに拡張を追加することもできます。プロトコルに準拠したクラスで関数を実装できますが、サブクラスで関数funcをオーバーライドすることもできます。 私はまだ、クラスではなくプロトコルを使用する必要があるという理由で、混乱しています。クラスの代わりにプロトコルを使用する必要があるときなぜプロトコルは迅速にクラスより優れていますか?
答えて
ダウンロードの例を取ってください。
あなたはFileDownloadModel基本クラスを持っており、3つのサブクラスAudioFileDownloadModel、VideoFileDownloadModel、ImageDownloadModelを持っています。
あなたはFileDownloadModelとして入力を受け取り、ファイルをダウンロードするには、モデルのそのurlToDownloadプロパティを使用していますDownloadManagerを持っています。
後にラインの下のあなたがそこに来て1つの以上のモデルであるが、そのようなUserDownloadModelサブクラスからユーザー、と言われています。
ここで、ダウンロード方法を組み込むために多くのコードを変更する必要があるこのようなシナリオを処理するのが難しくなりました。
プロトコル指向プログラミングは、ここであなたを助ける方法:
- がDownloadingFileProtocolという名前のプロトコルを作成し、ファイルをダウンロードするために必要な メソッドを追加します。例えば。 urlToDownload、 pathToSave、拡張等
- FileDownloadModelで同じプロトコルを実装し UserDownloadModel。 のコードを多く変更する必要がないという利点を参照してください。UserDownloadModel メソッドは、ダウンロードファイルプロトコルから実装するだけです。
- もう一度新しいエンティティがラインを下ってきたら、 のコードを変更するだけでプロトコルメソッドを実装することはできません。
- そして今、あなたのDownloadManagerが DownloadingFileProtocolの代わりに、特定のモデルとしての入力を取ることができ、今あなたが ダウンロードなど任意のモデルを作ることができます。
プロトコルを使用すると、1つのクラス/構造体を異なるものとして使用できます。たとえば、String
構造体は、多くのプロトコルに対応しています。
Comparable
CustomDebugStringConvertible
Equatable
ExtendedGraphemeClusterLiteralConvertible
Hashable
MirrorPathType
OutputStreamType
Streamable
StringInterpolationConvertible
StringLiteralConvertible
UnicodeScalarLiteralConvertible
これは、String
が11種類の異なるものとして使用できることを意味します。メソッドが上記のプロトコルのいずれかをパラメータとして必要とする場合は、文字列を渡すことができます。
"しかし、私はプロトコルが持つすべてのメソッドを持つ神のクラスを作成することができます!"あなたは主張した。覚えておいてください。あなたはSwiftの1つのクラスだけを継承することができます。多重継承は非常に危険なので、コードを非常に複雑にすることができます。
また、プロトコルを使用すると、クラスのカスタム動作を定義できます。 String
のhashcode
メソッドは、Int
のメソッドと同じではありません。しかし、これらは両方ともこの機能と互換性があります:
func doStuff(x: Hashable) {
}
それはプロトコルの本当の不思議です。
最後に重要なのは、プロトコルです。です。プロトコルは、「一種の」または「として使用できる」という関係を表します。 XをYとして使うことができるとき、XはプロトコルYに従うのが理にかなっています。
ほとんどの場合、タイプの階層です。 Red
がColorful
を拡張 - - Cube
がShape
- 異なる形状:あなたが
GlowingRedCube
を表すオブジェクトを持っていますが、あなたが気に汎用コードの多くで使用されているタイプを持つようにしたいとしましょう照明の - 異なるタイプ -
Glowing
あなたが困っているIlluminated
を拡張します。 GlowingRedCube
はGlowingCube
がShape
まで拡張されていますが、非常に幅広いクラスが用意されていますし、柔軟性のないものもあります(SoftRedCube
を作りたければどうしたらいいでしょうか? )
Cube
を持っていて、イルミネーションとシェイプがプロパティになっている可能性がありますが、コンパイラのタイプチェックがうまくいかない場合:Room.lightUp()
メソッドを持っていて、それを渡す必要がありますCube
の場合は、そのタイプに照明が含まれているかどうかを確認する必要があります。 Illuminated
しか渡すことができないなら、コンパイラは試してみるとすぐにあなたを止めるでしょう。
プロトコルでは、これを分離することができます。は、Illuminated
プロトコル、Colorful
プロトコル、およびShape
プロトコルを実装できます。プロトコル拡張のために、機能のデフォルトの実装を含めることができるので、それを接続するために階層のレベルを選択する必要はありません。
struct GlowingRedCube: Shape, Colorful, Illuminated {
// ..
}
効果的に、プロトコルを使用すると、そのオブジェクトが何をするかにかかわらず、オブジェクトにビヘイビアを付けることができます。つまり、デリゲートやデータソースプロトコルのようなものに使用されている理由です。ほとんどの場合、ViewController
にそれらのオブジェクトを添付しても、基礎となるオブジェクトは関連性がないため、実装方法について柔軟にすることができます。
Swiftのプロトコルは基本的なものよりもはるかに優れています。クラス、構造体、列挙型などのさまざまなコード構造に接続できるため、非常に強力です。これにより、プログラミングプロトコルに最初に近づくことができます。このアプローチには、WWDC last yearという素晴らしいビデオがありますが、いくつかの異なるオブジェクト構造を最初に試してみて、問題を感じるのに役立ちます。
クラスとプロトコルは直交する概念です。プロトコルはクラスツリー全体を切断し、異種の祖先と1つ以上のクラスを結合します。
おそらく、もっと簡単に言えば:
- "クラス" オブジェクトが何であるかを定義します。
- "protocol"はオブジェクトが持つ動作を定義します。
ですから、クラスの車を持っている:
class Car {
var bodyStyle : String
}
とクラス色:
class Color {
var red : Int
var green : Int
var blue : Int
}
は今、多かれ少なかれ明らかに色と車は完全に無関係です、しかし、のは、私を想定しましょうどちらか一方を文字列に簡単に変換できるようにしたいので、次のようにデバッグすることができます:
print(Car(...))
まさにこの目的のため
又は
print(Color(...))
、スウィフト言語ので、我々は次に、車がそのプロトコルを使用して印刷することができる宣言することができるプロトコルCustomStringConvertible
を定義:
extension Car : CustomStringConvertible {
var description : String { get { return "Car: \(bodyStyle)" } }
}
及び色並びに:
extension Color : CustomStringConvertible {
var description : String { get { return "Color: \(red) \(green) \(blue)" } }
}
私は各クラスに1つの印刷方法が必要でしたが、今は1つの印刷方法が必要ですIKE:クラスがプロトコルを実装することを宣言すると、私は、彼らが実装され、(おそらく)期待されます何をしていることを知って、プロトコルのメソッドを使用することができます約束ですので
func print(data:CustomStringConvertible) {
let string = data.description
... bunch of code to actually print the line
}
これが可能です。
でも、ObjCの複数のプロトコルに準拠することはできませんでしたか?スウィフトはどのように違うのですか? – Honey
- 1. なぜ `boost :: any`は` void * `より優れていますか?
- 2. 迅速な変数paramが優れている、配列
- 3. SHOULDプロトコルは迅速に宣言されるべきですか?
- 4. 迅速な型のプロトコルの配列
- 5. なぜ迅速な文法の誤り
- 6. 割り当て中に構造体内の迅速なクラスがコピーによって渡されますか?
- 7. 迅速で、どのように私は、プロトコル
- 8. メソッドのクロージャはインスタンスを迅速に保持していますか?迅速で
- 9. スイッチケースのフォールスルーコンセプトが迅速に許可されないのはなぜですか?
- 10. なぜ#selector()が迅速に機能しないのですか
- 11. どのようにして迅速にプロトコルを「明示的に」実装できますか?それが不可能ならば、なぜですか?
- 12. 別の迅速なクラスからのトリガーアクション
- 13. なぜ私のスキャッタローンの性能はVc SIMDより優れていますか?
- 14. なぜ算術+はテキストよりも優先されますか?
- 15. ケース:私はSWIFT 2からの迅速な3に移行しています迅速な3
- 16. Boost :: multi_index。より迅速なソリューション?
- 17. なぜこの迅速なコードが間違っていますか?
- 18. ノンクラスターアプリはnodejsのクラスターアプリより優れているのはなぜですか?
- 19. クラスが迅速に準拠しているプロトコルを決定するにはどうすればよいですか?
- 20. なぜHeroku/Parseの「オブジェクトが見つかりません」というエラーが迅速に返されますか?
- 21. タイプ変換は、汎用プロトコルと迅速に競合しますか?
- 22. JSONをサーバーに迅速に投稿できないのはなぜですか?
- 23. なぜreturn型Observableがプリミティブ型より優れていますか?
- 24. なぜ異なる迅速なクラスの関数が呼び出されないのですか?
- 25. ユーザーの迅速な通知:なぜnextTriggerDateはnilですか?
- 26. なぜレキシカルスコープがコンパイラより優先されますか?
- 27. java.awt.Robot.createScreenCaptureへのより迅速な代替手段はありますか?
- 28. なぜ迅速に下線が必要なのですか?
- 29. それはObjective-Cのクラスが.Hに迅速プロトコルを実装することはでき
- 30. NumPyでは、より大きな配列がより迅速に作成されますか?
私の例です: 'Vehicle'と' BuildingMaterial'から継承する 'Wood'を継承した' Car'を 'Car'と' Wood'に 'burn'メソッドを追加したい場合は、プロトコルが最も適合するでしょう。 – tktsubota
WWDC 2015の[プロトコル指向プログラミング](https://developer.apple.com/videos/play/wwdc2015/408/)では、どのビデオを参照しているのかわかりませんが、詳細は、プロトコルのメリット。 – Rob