クリーンアーキテクチャの第10章で、Martinはインターフェイス分離原則の例を示しています。その例と彼の説明を理解するのに問題があります。
この例では、OPSというクラスを使用する3つの個別のユーザー(クラス)があります。 OPSには、op1、op2、およびop3の3つのメソッドがあります。これらはそれぞれ1人のユーザーのみが使用します(op1はUser1のみなど)。
Martinは、OPSに変更が加えられた場合でも、それらがすべてOPSに依存しているため、OPSに変更を加えると、他のクラスの再コンパイルが発生することを通知します。 (したがって、op2を変更すると、User1の再コンパイルが必要になります。)
したがって、メソッドごとに1つずつ、合計3つのインターフェースが必要であると彼は主張します。次に、OPSクラスはそれらすべてを実装します。ユーザーは自分が使用するインターフェイスのみを使用します。したがって、User1はInterface1のみを実装しています。
マーティンによれば、OPSでのops2の実装が変更された場合、User1は、たとえばUser1がop2を記述するインターフェイスを使用しないため、これにより、たとえばUser1の再デプロイメントが停止します。
私には疑問があり、いくつかのテストを行いました。 (Martinは明示的にJavaを使用したので、私も同様に使用しました。)インターフェースがなくても、OPSを変更してもユーザーは再コンパイルされません。
そして、そうしたとしても(私はそう思っていました)、3つのインターフェイスを使用して同じクラスに3つすべてを実装させることは、私にとっても意味がありません。そのクラスの変更では、すべてのユーザーがインターフェースを再コンパイルする必要があるのではないでしょうか?コンパイラーは、変更した場所を分離して、変更したメソッドを記述するインターフェースに依存するユーザーのみを再コンパイルするのに十分スマートですか?ちょっと疑わしいです。
この原則が私にとって意味のある唯一の方法は、OPSクラスを3つの異なるクラス、インターフェース、またはノーに分割する場合でした。それは私には理解できましたが、それは明らかにマーティンの答えではありません。
どんな助けでも大歓迎です。
その特定の例では、Javaを使用すると、実際にインターフェースの利点が隠されます。インターフェース(または、より一般的にはlate binding)は、依存関係。
Direct dependency Indirect dependency
================= ===================
+---------+ +-----------+
| Service | | Interface |
+---------+ +-----------+
^ ^ ^
| | |
+--------+ +---------+ +--------+
| Client | | Service | | Client |
+--------+ +---------+ +--------+
ただし、Javaはすでに遅いバインディングを使用しています。Javaコンパイラが生成する.classファイルは、意味のある方法でリンクされていません。代わりに、 C++の意味でのこの種のリンクは、JVMが.classファイルをロードする実行時の後半に発生します。そのため、Javaのコンパイルモデルに焦点を当てることは、ここでは誤解を招きます。意味のないインタプリタ言語の実装。
明確にするために:ポリモーフィズム(およびISPをより慎重に適用)によって直接の依存関係を壊すことは、事前コンパイルシステム(ほぼすべてのC++実装など)のコンパイル時間に大きな影響を与えます。これは、pImplなどのC++固有のイディオムにも関連しています。
はるかに普遍的なISPの利点は、不要な依存関係を回避することにより、システムが
不要な依存関係の1つは、特定のサービス実装へのクライアントの依存関係です。これは、ポリモーフィズム/インターフェースを介して回避できます(依存関係の逆転の原則と比較してください)。もう1つの不要な依存関係は、インターフェースの追加メソッドに対するコンシューマーの依存関係です。インターフェイスを小さく分離した状態に保つと、これらの余分な依存関係が最小限に抑えられます。
私にとってISPからの主な要点は
インターフェースを「実装」していなくても、クラスのパブリックメンバーは暗黙的なインターフェースを形成することに注意してください。
私には疑問があり、いくつかのテストを行いました。 (Martinは明示的にJavaを使用したので、私も同様に使用しました。)インターフェースがなくても、OPSを変更してもユーザーは再コンパイルされません。
これは、OPSのパブリックインターフェイスを変更しなかった場合、つまり、実装の詳細のみを変更した場合にのみ当てはまります。パブリックメソッドのシグネチャを追加、削除、または変更した場合、既存のコンシューマーが破壊される可能性があり、優れたビルドツールはユーザークラスを再コンパイルします。
そのクラスの変更では、すべてのユーザーがインターフェースを再コンパイルする必要があるのではないでしょうか?
クライアントがインターフェイスにのみ結合されている場合、インターフェイスが変更されない限り、クライアントを再コンパイルする必要はありません。 OPSがインターフェイスを正しく実装しない方法で変更されると、ユーザークラスではなくOPSでコンパイルエラーが発生します。
この原則が私にとって意味のある唯一の方法は、OPSクラスを3つの異なるクラス、インターフェース、またはノーに分割する場合でした。
クラスは「何かがどのように実装されるか」、インターフェイスは「私がそれで何ができるか」と考えてください。実装が3つのインターフェースすべてのサービスを提供する場合、単一のクラスが3つのインターフェースを実装することは理にかなっています。その場合、3つのクラスに分割しても意味がありません。