@ledsun blog

無味の味は佳境に入らざればすなわち知れず

デメテルの法則

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本に減ります。 変更するために、確認しなければいけない呼び出し元の数が一桁減ります。

デメテルの法則」を守ると依存関係が乗算で爆発するのを防げます。 そしてプログラムは変更容易になります。

参考