15

私は昨日休暇から仕事に戻ってきました。私たちの毎日のスタンドアップで、私のチームメイトは、Java コード内のすべてのモデル オブジェクトをリファクタリングして、すべてのゲッターとセッターを削除し、代わりにモデル フィールドをすべてパブリック オブジェクトにすることについて言及しました。そうする理由としてのデメテル

デメテルの法則を順守しやすくするため: モジュールは、操作する「オブジェクト」の内部について認識してはなりません。データ構造には動作が含まれていないため、内部構造が自然に公開されます。その場合、デメテルは適用されません。

LoD に関する知識をブラッシュアップしなければならなかったことは認めますが、これが法律の精神の範囲内であることを示すものは、私の人生では何も見つかりません。私たちのモデルの getter/setter にはビジネス ロジックが含まれていないため、これらのオブジェクトのクライアントは get/set メソッド内で実行されているビジネス ロジックがあるかどうかを理解する必要がありません。

これは、「オブジェクト構造の内部知識」が必要であることの意味を誤解していると思います。少なくとも、文字通りに解釈しすぎて、その過程でかなり標準的な慣習を破っています。

私の質問は、LoD の名前でゲッター/セッターを介してではなく、モデル オブジェクトの内部構造を直接公開することに実際に意味があるのでしょうか?

4

3 に答える 3

13

この変更がデメテルの法則と関係があるようには思えません。基本的に、この法則は、他のオブジェクトのチェーン全体を通じてメソッドを呼び出すことによって、オブジェクト グラフの構造をコードにエンコードすることに関するものです。たとえば、自動車保険アプリケーションで、顧客に保険証券があり、保険証券に車両があり、車両にドライバーが割り当てられ、ドライバーに生年月日と年齢があるとします。次のコードを想像できます。

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 メソッドを設定します。PolicyPolicy

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たとえば、 を渡すとスロー) が関連付けられている必要があります。その文脈でデメテルの法則が発動されたのは聞いたことがありません。

于 2014-09-24T16:37:44.770 に答える