Law of Demeter
直接の友達とだけ話すこと
最小知識の原則、ともいいます。
どんなときに使うの?
ドットいっぱい使ってるとき

ふんふーん♪
Console.log(student.getClass().getName())



ドットいっぱいつなげるのダメ!組み合わせ爆発起こるから!
ドットがつながる=組み合わせ爆発
ドットいっぱい問題
オブジェクト指向プログラミング言語では、ドット(.)はメソッド呼び出しを表します。
objectA.method()
で、object の method を呼び出せます。返却されるのは、メソッドの戻り値です。
ここで、戻り値がオブジェクトであった場合、そのオブジェクトに対して、またドットで呼び出せます。
objectA.getObjectB().method()
これが連なると、どんどんドットがいっぱいになっていきます。
objectA.getObjectB().getObjectC().getObjectD().method()
組み合わせ爆発
ドットがいっぱいになると、なにが良くないのか。クラス図で考えます。
クラスAがクラスBを呼び出すとき、クラスAからクラスBへの依存関係が生まれます。


呼び出しが、A→B→C の場合、A→B、B→C はもちろんのこと、A→Cの依存関係も生まれます。


さらに、A→B→C→D の場合は、依存関係がさらに多くなります。


依存関係は、依存先に変更が入ると、依存元に影響が及びます。
クラスAは、クラスB/クラスC/クラスDのいずれに変更が入っても、その影響が及ぶ状態です。
このような、依存関係が膨大になる状態が、組み合わせ爆発です。
こうなると、たとえ一箇所の変更でも、影響が広範囲に及んでしまうことになります。
使えるドットはひとつだけ
では、オブジェクトはどのようなメソッドなら呼び出してよいの?指針があります。
- そのオブジェクト自身のメソッド
- オブジェクトが所有するオブジェクトのメソッド
- メソッドの引数で渡されたオブジェクトのメソッド
- メソッドの内部で生成したオブジェクトのメソッド
プログラムで見てみましょう。
class ClassA {
ClassB objectB;
private void funcInner() {
...
}
public void func(ClassC objectC) {
// ○ オブジェクト自身のメソッド
this.funcInner();
// ○ オブジェクトが所有するオブジェクトのメソッド
this.objectB.func();
// ○ メソッドの引数で渡されたオブジェクトのメソッド
objectC.func();
// ○ メソッドの内部で生成したオブジェクトのメソッド
ClassD objectD = new ClassD();
objectD.func();
// × オブジェクトから取得したオブジェクトのメソッドは呼んではいけない
objectD.getObectE().func();
}
}
これを見て分かるように「使えるドットはひとつだけ」というルールになっています。
つまり、あなたが話せるのは、あなたの直接の友達だけ。あなたの友達の友達には話しかけるな、ということです。
これにより、必要以上の複雑な関連性を避け、安定性の高いプログラムとなります。
メソッドチェーンは例外
ただし、以下のような例は、例外です。
double average = numbers.stream()
.mapToInt(Integer::intValue)
.average()
.orElse(0.0);
asyncTask1()
.then(result1 => {
console.log(result1);
return asyncTask2();
})
.then(result2 => {
console.log(result2);
})
.catch(error => {
console.error(error);
});
メソッドチェーン、と呼ばれるテクニックです。
ドット演算子で、自身のオブジェクト(または同種のオブジェクト)をリターンし、メソッドをつなげていきます。オブジェクトに対する機能拡張を、簡潔で読みやすく書けるようにしています。
これは、関連性を拡大しているわけではないので、例外と考えてください。
まとめ
ことプログラミングにおいては、他者との関係性は、できるだけ少ないほうがよいのです。
友達の友達に、いきなり話しかけてお願いするのは、やめましょう。
現実の生活では…友達の友達とも、仲良くできるに越したことはないですね。
コメント