DDDなどが話題になるたびに「オブジェクト指向プログラミングってTell, Don't AskしたいだけでDDDでもデザインパターンでもクリーンアーキテクチャでもその実現手段なのではないかなあ?」などと思うことがあります。 ところでTell, Don't Askってなんでしたっけ? 「AskするなTellせよ」って言われてもよくわかりません。 「聞くじゃない聴くなんだ」みたいな言葉遊びの雰囲気を感じます。 言葉遊びは必要なコンテキストが多くすぎて、ネイティブじゃないとなかなかピンとこないですよね。
で、Tell, Don't Askを調べると高確率で「デメテルの法則」が抱き合わせで現れます。 これって同じものなんですか?違うものなんですか? まずは「デメテルの法則」について
デメテルの法則
Law of Demeter: Principle of Least Knowledge によるとデメテルの法則は
Only talk to your friends
DeepL翻訳すると「友達にしか話さない」です。 具体的にはどういうことでしょうか?
デメテルの法則を厳密に守るにはどうすればいいの? - Qiitaでは次のコードがUserServiceクラスないで呼び出されることを「デメテルの法則」に反するとあげられています。
User.BasicInfo.Configuration.Addon.IsEnabled
UserServiceとUserが友達です。 BasicInfoやConsultationは友達ではありません。
「友達にしか話さない」とはどういうことでしょうか?
User.IsAddonEnabled
と呼び出すことです。
友達でないBasicInfoやConsultationと話すのはUserの仕事です。
「デメテルの法則」を守ると何がうれしいのでしょうか? 前述のQiita記事に良い図があります。
この図の何がいいかといいますと、補助線が引きやすいのです。
元の図ではUserServiceからUserクラスにUse線が引かれていました。 実際にはUserServiceは次の4つのクラスを使っています。
- User
- BasicInfo
- Configuration
- Addon
これらの4つのクラスを変更するとき、UserServiceに影響が出ないか考える必要があります。
UserService一か所でこの使い方をしている分には問題ありません。
アプリケーションの複数個所から同様の使い方をしていると問題になります。
たとえば4つのサービスクラスにUser.BasicInfo.Configuration.Addon.IsEnabled
が書かれていたらどうなるでしょうか?
依存線は4 x 4 = 16 本になります。
16本の依存関係をかいくぐって修正をするのは大変です。
一か所User.IsAddonEnabled
でラップできれば、依存線は3本に減ります。
変更するために、確認しなければいけない呼び出し元の数が一桁減ります。
「デメテルの法則」を守ると依存関係が乗算で爆発するのを防げます。 そしてプログラムは変更容易になります。