インターフェイスの棲み分け原理はこう述べています。
クライアントは、使用しないメソッドに依存することを強制されるべきではありません。ISPは、非常に大きいインターフェイスをより小さく、より具体的なインターフェイスに分割します。これにより、クライアントは、関心のあるメソッドについてのみ知る必要があります。
ここには未回答の質問がいくつかあります。1つは:
どれくらい小さい?
あなたは言う:
現在、クライアントの要件に応じてモジュールの名前空間を分割することでこれに対処しています。
私はこのマニュアルをダックタイピングと呼んでいます。クライアントが必要とするものだけを公開するインターフェースを構築します。インターフェイスの分離の原則は、単に手動でアヒルを入力するだけではありません。
ただし、ISPは、再利用可能な「一貫性のある」役割インターフェイスの単なる呼び出しではありません。「一貫性のある」役割のインターフェース設計では、独自の役割のニーズを持つ新しいクライアントの追加を完全に防ぐことはできません。
ISPは、サービスへの変更の影響からクライアントを隔離する方法です。変更を加えたときにビルドを高速化することを目的としていました。確かに、クライアントを壊さないなど、他の利点もありますが、それが主なポイントでした。サービスcount()
関数のシグネチャを変更する場合、使用count()
しないクライアントを編集および再コンパイルする必要がないと便利です。
これが、インターフェイス分離の原則に関心がある理由です。それは私が重要であると信じているものではありません。それは本当の問題を解決します。
そのため、それを適用する方法で問題を解決する必要があります。必要な変更の正しい例だけで打ち負かすことのできないISPを適用するための脳死の方法はありません。あなたは、システムがどのように変化しているかを見て、物事を静かにさせる選択をすることになっています。オプションを調べてみましょう。
最初に自問してください:現在、サービスインターフェイスの変更は困難ですか?そうでない場合は、外に出て、落ち着くまで遊びます。これは知的運動ではありません。治療法が病気より悪くないことを確認してください。
多くのクライアントが同じ機能のサブセットを使用する場合、それは「一貫した」再利用可能なインターフェースを主張します。サブセットは、サービスがクライアントに提供している役割と考えることができる1つのアイデアに焦点を当てている可能性があります。これがうまくいくと便利です。これは常に機能するとは限りません。
多くのクライアントが異なる機能のサブセットを使用している場合、クライアントが実際に複数のロールを介してサービスを使用している可能性があります。それは大丈夫ですが、それは役割を見にくくします。それらを見つけて、それらをバラバラにしてみてください。これにより、ケース1に戻ります。クライアントは、複数のインターフェイスを介してサービスを使用するだけです。サービスのキャストを開始しないでください。サービスをクライアントに複数回渡すことを意味するものがある場合。それは機能しますが、サービスが分割する必要がある大きな泥の塊ではないかどうか疑問に思います。
多くのクライアントが異なるサブセットを使用しているが、クライアントが複数を使用することを許可するロールさえ表示されない場合、インターフェースを設計するためにアヒルを入力することほど良いものはありません。インターフェースを設計するこの方法により、クライアントは使用していない1つの関数にもさらされないことが保証されますが、新しいクライアントの追加には、サービス実装が知る必要のない新しいインターフェースの追加が必ず含まれることがほぼ保証されますそれについては、役割インターフェースを集約するインターフェースが行います。私たちは、ある痛みを別の痛みと交換しただけです。
多くのクライアントが異なるサブセットを使用する場合、オーバーラップし、予測できないサブセットを必要とする新しいクライアントが追加されることが予想されます。サービスを分割したくない場合は、より機能的なソリューションを検討してください。最初の2つのオプションは機能せず、パターンに従わないものがあり、さらに変更が加えられる悪い場所にいるので、各機能を独自のインターフェイスにすることを検討してください。ここで終わるということは、ISPが失敗したということではありません。何かが失敗した場合、それはオブジェクト指向のパラダイムでした。単一メソッドインターフェイスは、極端にISPに従います。これはかなりのキーボード入力ですが、これによりインターフェイスが突然再利用可能になることがあります。繰り返しになりますが、
だから、彼らは確かに非常に小さくなります。
私はこの質問を、最も極端な場合にISPを適用するための挑戦とみなしました。ただし、極端なことは避けるのが最善です。他のSOLID原則を適用するよく考えられた設計では、これらの問題は通常発生せず、ほとんど問題になりません。
別の未回答の質問:
これらのインターフェースの所有者は誰ですか?
「ライブラリ」メンタリティと呼ばれるもので設計されたインターフェイスが何度も見られます。私たちは皆、あなたが何かをしているだけで、それがあなたがそれを見た方法だから、monkey-see-monkey-doコーディングの罪を犯しました。インターフェースについても同じことを犯しています。
私が考えるライブラリのクラス用に設計されたインターフェイスを見ると、ああ、これらの人はプロです。これは、インターフェースを行う正しい方法でなければなりません。私が理解できなかったのは、図書館の境界には独自のニーズと問題があるということです。ひとつには、ライブラリはそのクライアントの設計について完全に無知です。すべての境界が同じというわけではありません。また、同じ境界でさえ、それを横断する方法が異なる場合があります。
以下に、インターフェース設計を調べるための2つの簡単な方法を示します。
サービス所有インターフェース。一部の人々は、サービスが実行できるすべてを公開するためにすべてのインターフェースを設計します。IDEでリファクタリングオプションを見つけることもできます。このオプションは、フィードするクラスを使用してインターフェイスを作成します。
クライアント所有のインターフェース。ISPはこれが正しいと主張しているようで、所有するサービスは間違っています。クライアントのニーズを念頭に置いて、すべてのインターフェイスを分割する必要があります。クライアントはインターフェイスを所有しているため、定義する必要があります。
だから誰が正しい?
プラグインを検討してください:

ここのインターフェースの所有者は誰ですか?クライアント?サービス?
両方が判明。
ここの色はレイヤーです。赤いレイヤー(右)は緑のレイヤー(左)について何も知らないはずです。緑のレイヤーは、赤のレイヤーに触れることなく変更または置換できます。これにより、緑のレイヤーを赤のレイヤーにプラグインできます。
何について何を知るべきか、何を知らないかを知るのが好きです。私にとって、「何が何を知っているのか」は、最も重要な建築上の疑問です。
いくつかの語彙を明確にしましょう。
[Client] --> [Interface] <|-- [Service]
----- Flow ----- of ----- control ---->
クライアントは使用するものです。
サービスは使用されるものです。
Interactor
たまたま両方です。
ISPは、クライアントのインターフェイスを分割すると言います。いいでしょう、ここにそれを適用しましょう:
Presenter
(サービス)はOutput Port <I>
インターフェースに指示しないでください。インターフェースはInteractor
(ここではクライアントとして機能する)必要なものに絞り込む必要があります。つまり、インターフェイスInteractor
はISP について知っており、ISPに従うには、それに合わせて変更する必要があります。そしてこれは大丈夫です。
Interactor
(ここではサービスとして動作します)は、Input Port <I>
インターフェースに指示するべきではありません。インターフェイスはController
(クライアント)が必要とするものに狭める必要があります。つまり、インターフェイスController
はISP について知っており、ISPに従うには、それに合わせて変更する必要があります。そして、これは大丈夫ではありません。
赤のレイヤーは緑のレイヤーを認識していないため、2番目のレイヤーは問題ありません。ISPは間違っていますか?まあ...ちょっと。絶対的な原則はありません。これは、サービスが実行できるすべてを表示するためのインターフェイスを好む人が正しいと判明した場合です。
少なくとも、Interactor
このユースケースが必要とするもの以外に何もしなければ、彼らは正しい。Interactor
が他のユースケースのために物事を行う場合、これInput Port <I>
について知る必要がある理由はありません。なぜInteractor
1つのユースケースだけに焦点を当てることができないのかわからないため、これは問題ではありませんが、何かが起こります。
しかし、input port <I>
インターフェースは単純にController
クライアントにそれ自体を従属させることができず、これを真のプラグインにすることができます。これは「ライブラリ」境界です。まったく異なるプログラミングショップが、赤のレイヤーが公開されてから数年後に緑のレイヤーを書くこともできます。
「ライブラリ」の境界を越えて、反対側のインターフェイスを所有していないのにISPを適用する必要があると感じる場合、インターフェイスを変更せずに絞り込む方法を見つける必要があります。
それを実現する1つの方法はアダプターです。のようなクライアントControler
とInput Port <I>
インターフェースの間に置きます。アダプタはInteractor
として受け入れ、Input Port <I>
作業を委任します。ただし、Controller
グリーンレイヤーが所有するロールインターフェースを介して、クライアントが必要とするもののみを公開します。アダプタはISP自体には従いませんが、ISP Controller
を楽しむような複雑なクラスを許可します。これはController
、使用するアダプターよりもアダプターの数が少ない場合や、ライブラリの境界を越えて、公開されているにもかかわらずライブラリの変更が止まらないという異常な状況にある場合に便利です。Firefoxを見ています。現在、これらの変更はアダプターを破壊するだけです。
これはどういう意味ですか?正直なところ、あなたが何をすべきかを伝えるのに十分な情報を提供していないことを意味します。ISPに従わないことが問題の原因であるかどうかはわかりません。それに従うことで、さらに問題が発生しないかどうかはわかりません。
あなたがシンプルなガイド原則を探しているのを知っています。ISPはそれを目指しています。しかし、多くのことは言われていません。私はそれを信じています。はい、正当な理由がない限り、クライアントが使用しないメソッドに依存することを強制しないでください!
プラグインを受け入れるように何かを設計するなど、正当な理由がある場合は、ISPの原因に従わない問題(クライアントに影響を与えずに変更するのは難しい)、およびそれらを緩和する方法(1つの安定した状態に保つInteractor
か、少なくともInput Port <I>
焦点を合わせる)に注意してください使用事例)。