ProgrammingiOS開発者

Swiftにおけるプロトコルの抽象化がどのように機能するか、クラスの継承とどのように異なるかを説明してください。クラスの階層の代わりにプロトコルを使用すべき時はいつですか?

Hintsage AIアシスタントで面接を突破

答え。

問題の歴史:

プロトコルの抽象化は、Swiftでオブジェクト指向プログラミングのクラス的継承に対抗して登場しました。Objective-Cや他のOOP言語では、「一般から特殊への」継承のアプローチが支配的でしたが、Swiftは初期からプロトコルを主な抽象化手段として推進し、継承の上に構成を強調しました。

問題:

従来の継承は厳格な階層を想定しており、サブクラスのツリーがあり、overrideによって必ず拡張される必要があります。これは柔軟性を制限し、「壊れやすい」コードを生み出し、リファクタリングを難しくし、基底クラスの肥大化を引き起こします。さらに、Swiftではクラスの多重継承がサポートされていないため、機能の再利用は他のメカニズムを通じてのみ可能です。

解決策:

プロトコルの抽象化により、型が実装しなければならない「要求のセット」を宣言することができます。プロトコルは共通のロジックを注入するために拡張 (extension) することができ、これにより「ミックスイン」の概念に近づきます。

コードの例:

protocol Drawable { func draw() } extension Drawable { func draw() { print("デフォルトの描画") } } struct Circle: Drawable {} let c = Circle() c.draw() // "デフォルトの描画"が出力されます

主な特徴:

  • プロトコルは多重構成をサポート(複数の要求)。
  • 厳格な階層を作成しない — 拡張が容易で、アーキテクチャを壊さない。
  • 値型(struct/enum)とクラスの両方で機能できる、これは継承では不可能です。

陥れる質問。

プロトコルのextensionとクラスの通常の実装の違いは何ですか?

プロトコルを通じたextensionは、ユーザーが自分の型でこのメソッドを実装していない場合にのみ、デフォルトの実装を追加します。メソッドが型で明示的に実装されている場合、それが呼び出されます。

例:

protocol Demo { func foo() } extension Demo { func foo() { print("デフォルト") } } struct X: Demo { func foo() { print("カスタム") } } X().foo() // "カスタム"

プロトコルを実装している型とそのextensionにデータとしてアクセスした場合に何が起こりますか?

プロトコルがメソッドを必須(要求)として宣言する場合、プロトコル型にキャストしても、特定の型の実装が使用されます。ただし、extensionに新たに(プロトコルで以前に宣言されていない)プロパティが追加された場合、それはextensionを通じてのみアクセス可能で、プロトコル型ではアクセスできません。

異なるstructを持つインスタンスをプロトコル実装の配列に保存できますか?

はい — 「存在的」型(例: [Drawable])のおかげで、異種コレクションを保存できます:

struct Tri: Drawable { func draw() { print("三角形") } } let arr: [Drawable] = [Circle(), Tri()] arr.forEach { $0.draw() }

一般的なエラーとアンチパターン

  • 一般的なインターフェースのために太ったスーパークラスから継承する代わりにプロトコルに分割する
  • プロトコルでの明示的な要求なしのextensionの過剰使用
  • associatedtypeを持つプロトコルをコレクションに保持しようとすること ([SomeProtocol]) — これはサポートされていません

実生活の例

ネガティブケース

会社には基本的なスーパークラス Shape があり、すべての図形(Circle、Square、Polygon)が継承されていました。基本クラスは肥大化し、各新しい図形をoverrideでサポートしなければならなくなりました。システムの拡張はますます難しくなり、各新しい型がABIを壊し、既存のコードを再記述させていました。

利点:

  • 基本クラスを介した新しい共通メソッドの迅速な導入

欠点:

  • 依存関係が過剰なモノリスの階層
  • 階層外での再利用が悪い
  • overrideメソッドの衝突

ポジティブケース

複数のプロトコル DrawableColorableAnimatable を使用することにしました。これにより、各図形を他の構造を変更せずに「アニメーション可能かつ色付き」に簡単にすることができました。新しい機能はextensionを通じて追加されます。

利点:

  • 柔軟性、容易な保守性と拡張性
  • 異なる文脈での改善された再利用性

欠点:

  • API設計とassociatedtypeの知識が必要です