この変更がデメテルの法則と関係があるようには思えません。基本的に、この法則は、他のオブジェクトのチェーン全体を通じてメソッドを呼び出すことによって、オブジェクト グラフの構造をコードにエンコードすることに関するものです。たとえば、自動車保険アプリケーションで、顧客に保険証券があり、保険証券に車両があり、車両にドライバーが割り当てられ、ドライバーに生年月日と年齢があるとします。次のコードを想像できます。
public boolean hasUnderageDrivers(Customer customer) {
for (Vehicle vehicle : customer.getPolicy().getVehicles()) {
for (Driver driver : vehicle.getDrivers()) {
if (driver.getAge() < 18) {
return true;
}
}
}
return false;
}
このコードは、知る必要のない内部の知識を持っているため、これはデメテルの法則に違反します。ドライバーが保険契約全体に割り当てられているだけでなく、車両に割り当てられていることを認識しています。将来、保険会社が、ドライバーを特定の車両に割り当てるのではなく、単に保険に加入させると決定した場合、このコードを変更する必要があります。
getPolicy()
問題は、そのパラメータのメソッドを呼び出すgetVehicles()
ことgetDrivers()
ですgetAge()
。デメテルの法則では、クラスのメソッドは次のものに対してのみメソッドを呼び出すべきであると述べています。
- 自体
- そのフィールド
- そのパラメータ
- 作成するオブジェクト
(最後のものは、ローカルで直接作成するのではなく、ファクトリによってオブジェクトを注入または作成する必要がある単体テストの問題になる可能性がありますが、それはデメテルの法則とは関係ありません。)
この問題を解決するには、オブジェクトをhasUnderageDrivers()
渡し、ポリシーに未成年者のドライバーが含まれているかどうかを判断する方法を知っているon メソッドを設定します。Policy
Policy
public boolean hasUnderageDrivers(Policy policy) {
return policy.hasUnderageDrivers();
}
1 レベル下の を呼び出してもcustomer.getPolicy().hasUnderageDrivers()
、おそらく問題ありません。デメテルの法則は経験則であり、厳格な規則ではありません。また、変更される可能性が低いことについては、あまり心配する必要はありません。Driver
おそらく常に生年月日とgetAge()
メソッドを持ち続けるでしょう。
しかし、あなたのケースに戻ると、これらすべての getter を public フィールドに置き換えるとどうなるでしょうか? デメテルの法則にはまったく役に立ちません。最初の例とまったく同じ問題が発生する可能性があります。検討:
public boolean hasUnderageDrivers(Customer customer) {
for (Vehicle vehicle : customer.policy.vehicles) {
for (Driver driver : vehicle.drivers) {
if (driver.age < 18) {
return true;
}
}
}
return false;
}
(単純なフィールドではなく、生年月日に基づく計算になる可能性がありますが、に変換driver.getAge()
したこともあります。)driver.age
getter の代わりにパブリック フィールドを使用してコードを記述した場合、オブジェクト グラフがどのようにまとめられるか (顧客には、ドライバーを備えた車両を持つポリシーがあります) に関する知識を埋め込むことに関して、まったく同じ問題が存在することに注意してください。問題は、ゲッターが呼び出されるかどうかではなく、ピースがどのようにまとめられるかに関係しています。
ちなみに、(final?) パブリック フィールドよりもゲッターを優先する通常の理由は、後でそれらの背後に何らかのロジックを配置する必要がある場合があるためです。age は生年月日と今日の日付に基づく計算に置き換えられます。または、setter に何らかの検証 (null
たとえば、 を渡すとスロー) が関連付けられている必要があります。その文脈でデメテルの法則が発動されたのは聞いたことがありません。