アジャイル開発者に不可欠なスキル、ニーズと機能のインターフェース、第 12 章では、著者がこの章の終わりまでに言及している DEMETER の法則を適用するという課題に対して提案された主な解決策を理解しようとしています。
話を短くするために。
次のスタディ ケースから始めます。
public class City {
public string name{};
public City twinCity{};
public Street[] streets{};
}
public class Street {
public string name{};
public House[] houses{};
}
public class House {
public int number{};
public Color color{};
}
著者は次のように述べています。
このようなモデルは、カプセル化するのではなく、公開することを奨励します。コードに特定の City インスタンスへの参照が含まれている場合 (たとえば、シアトルをマップするインスタンス)、メイン ストリート 1374 番地の家の色が必要な場合は、次のようにします。
public Foo() {
Color c = Seattle.streets()["Main"].
houses()[1374].
color();
}
これが一般的な慣行として行われる場合の問題は、システムがあらゆる場所で依存関係を開発し、このモデルの任意の部分を変更すると、これらの依存関係のチェーンの上下に影響を与える可能性があることです。ここで、「見知らぬ人と話すな」2 というデメテルの法則の出番です。これは、関数/メソッドのデメテルの法則としてオブジェクト システムで形式化されています。オブジェクト O のメソッド M は、次の種類のオブジェクトのメソッドのみを呼び出すことができます。
- オーズ
- M のパラメーター
- M 内でインスタンス化されたすべてのオブジェクト
- O の直接コンポーネント オブジェクト
- O によってアクセス可能なグローバル変数
そして、DEMTERの法則を適用するときは、次のようなものを目指すべきであることを提案します
public Foo() {
Color c = Seattle.ColorOfHouseInStreet("Main",1374);
}
そして、次のことからすぐに警告します。
これは最初は賢明なポリシーのように見えますが、特定のエンティティのインターフェイスが文字通り関連するものすべてを提供することが期待できるため、すぐに手に負えなくなる可能性があります。これらのインターフェイスは時間の経過とともに肥大化する傾向があり、実際、特定のグラスが最終的にサポートする可能性のあるパブリック メソッドの数にはほとんど終わりがないように思われます。
次に、結合と依存関係の問題を説明する際の簡単な回り道の後、サービスのインターフェースによってクライアントとそのサービスを分離することの重要性に言及し、さらにクライアントを「サービス機能」から「インターフェースが必要」に分離することによって、彼は言及します。理想的であるが必ずしも実用的ではないものとしてアダプターを使用することによる「インターフェイス」。
彼は、問題を解決するために、以下に説明するファサード パターンを使用して、DEMETER の法則とニーズ/機能の分離を組み合わせることができると提案しています。
元の依存関係から
デメテルの法則とニーズ/機能の境界面の分離を適用すると、最初に次のことが得られます。
しかし、特にモッキングの観点からは非現実的であることを考えると、次のようにファサードを使用してより単純なものを作成できます。
問題は、デメテルの法則に違反しないという問題を正確に解決する方法がわからないことです。元のクライアントと元のサービスの間の法律を維持していると思います。しかし、FACADE 内で違反を移動しただけです。