今回は”デメテル(Demeter)の法則”について紹介していきます。
”デメテル(Demeter)の法則”とは?
”デメテル(Demeter)の法則”は、ソフトウェア開発、特にオブジェクト指向プログラミングにおける設計ガイドラインです。
これは、コンポーネント間の結合を最小限に抑え、モジュール性と保守性を向上させることを目的としています。
別の言い方で表現すると、「オブジェクトは直接関係のあるオブジェクトとだけやり取りするべき」ということです。つまり、間接的なオブジェクトには依存しないようにするという原則です。
…といってもやっぱりわからない!という方に説明すると
みたいなイメージです。
主なポイントは以下の通りです。
定義
Demeterの法則は、オブジェクトのメソッドが呼び出すべきメソッドを以下に限定するというものです。
- 自分自身のメソッド
- 引数として渡されたオブジェクトのメソッド
- 自分が生成したオブジェクトのメソッド
- 自分の直接のコンポーネントオブジェクトのメソッド
目的
クラス間の依存関係を減らし、システムをより堅牢で保守しやすくすることが主な目的です。
各オブジェクトが他のオブジェクトについて関与することを制限することで、システムの一部に変更があっても他の部分に影響を与えにくくなります。
友達の例で言うと
みたいな感じです。
例
// Demeterの法則を守らない場合
order.getCustomer().getAddress().getCity();
// Demeterの法則を守る場合
order.getCustomerCity();
利点
- 保守性の向上
オブジェクト間の依存関係が少なくなるため、システムの一部を変更しても他の部分に影響を与えにくくなります。これにより、コードの修正や拡張が容易になります。
- 可読性の向上
各オブジェクトが自分の責任範囲内で動作するため、コードが直感的で理解しやすくなります。これにより、新しい開発者がプロジェクトに参加した際の学習コストが低減します。
- 再利用性の向上
コンポーネントが独立して動作するため、他のプロジェクトや異なるコンテキストで再利用しやすくなります。これにより、開発効率が向上します。
- テストの容易さ
依存関係が少ないため、ユニットテストが容易になります。各コンポーネントを独立してテストできるため、バグの早期発見と修正が可能になります。
- 堅牢性の向上
システム全体の結合度が低いため、予期しない変更やエラーに対する耐性が高まります。これにより、システムの信頼性が向上します。
- 設計の一貫性
Demeterの法則を遵守することで、設計の一貫性が保たれ、コードベース全体が統一されたスタイルで書かれるようになります。これにより、コードレビューや共同作業がスムーズに進みます。
批判
Demeterの法則は良い実践を促進しますが、ラッパーメソッドが増えすぎてコードが煩雑になることもあります。
ラッパーメソッド(Wrapper Method)は、プログラミングやソフトウェア開発の分野でよく使われる概念です。簡単に言うと、既存の機能やコードを「包み込む」ことで、使いやすくしたり、機能を拡張したりする方法を指します。
Demeterの法則の具体的な例
Demeterの法則の具体的な例をいくつか紹介します。
例1: シンプルなオブジェクト関係
// Demeterの法則を守らない場合
class Order {
Customer customer;
public String getCustomerCity() {
return customer.getAddress().getCity();
}
}
class Customer {
Address address;
public Address getAddress() {
return address;
}
}
class Address {
String city;
public String getCity() {
return city;
}
}
// Demeterの法則を守る場合
class Order {
Customer customer;
public String getCustomerCity() {
return customer.getCity();
}
}
class Customer {
Address address;
public String getCity() {
return address.getCity();
}
}
class Address {
String city;
public String getCity() {
return city;
}
この例では、Order
クラスがCustomer
クラスの内部構造に依存しないようにしています。これにより、Customer
クラスやAddress
クラスの変更がOrder
クラスに影響を与えにくくなります。
例2: メソッドチェーンの回避
// Demeterの法則を守らない場合
class Car {
Engine engine;
public Engine getEngine() {
return engine;
}
}
class Engine {
Oil oil;
public Oil getOil() {
return oil;
}
}
class Oil {
public void checkLevel() {
// オイルレベルをチェックする処理
}
}
class Mechanic {
public void checkCarOil(Car car) {
car.getEngine().getOil().checkLevel();
}
}
// Demeterの法則を守る場合
class Car {
Engine engine;
public void checkOil() {
engine.checkOil();
}
}
class Engine {
Oil oil;
public void checkOil() {
oil.checkLevel();
}
}
class Oil {
public void checkLevel() {
// オイルレベルをチェックする処理
}
}
class Mechanic {
public void checkCarOil(Car car) {
car.checkOil();
}
この例では、Mechanic
クラスがCar
クラスの内部構造に依存しないようにしています。これにより、Car
クラスやEngine
クラスの変更がMechanic
クラスに影響を与えにくくなります。
他の原則との違いは?
Demeterの法則は、他の設計原則と組み合わせて使うことで、より効果的なソフトウェア設計が可能になります。以下に、いくつかの主要な設計原則との違いを説明します。
- 単一責任の原則(SRP: Single Responsibility Principle)
- SRPは、クラスやモジュールが一つの責任を持つべきだとする原則です。Demeterの法則は、オブジェクト間の依存関係を最小限に抑えることに焦点を当てていますが、SRPは各クラスが一つの目的に専念することを強調します。
- 違い:SRPはクラスの内部構造に関するもので、Demeterの法則はクラス間のインタラクションに関するものです。
- オープン・クローズドの原則(OCP: Open/Closed Principle)
- OCPは、ソフトウェアエンティティ(クラス、モジュール、関数など)は拡張に対して開かれているべきだが、変更に対して閉じているべきだとする原則です。Demeterの法則は、オブジェクトが他のオブジェクトへの関与を制限することで、システムの変更に強くします。
- 違い:OCPは拡張性と安定性を重視し、Demeterの法則は依存関係の管理を重視します。
- リスコフの置換原則(LSP: Liskov Substitution Principle)
- LSPは、派生クラスはその基底クラスと置き換え可能でなければならないとする原則です。Demeterの法則は、オブジェクトが直接関係のあるオブジェクトのみとやり取りすることを推奨します。
- 違い:LSPは継承関係における一貫性を重視し、Demeterの法則はメソッド呼び出しの範囲を制限します。
- 依存関係逆転の原則(DIP: Dependency Inversion Principle)
- DIPは、高レベルのモジュールは低レベルのモジュールに依存してはならず、両者は抽象に依存すべきだとする原則です。Demeterの法則は、オブジェクトが他のオブジェクトについて関与することを最小限に抑えることを目指します。
- 違い:DIPは依存関係の方向性を逆転させることを重視し、Demeterの法則は依存関係の数を減らすことを重視します。
これらの設計原則は、互いに補完し合うことで、より堅牢で保守しやすいソフトウェアを作成するのに役立ちます。どの原則も特定の側面に焦点を当てており、組み合わせて使用することで、全体的な設計品質を向上させることができます。
まとめ
今回の記事のポイントをまとめます。
- Demeterの法則は、コンポーネント間の結合を最小限に抑え、モジュール性と保守性を向上させる
- Demeterの法則の利点は
-
- 保守性の向上
- 可読性の向上
- 再利用性の向上
- テストの容易さ
- 堅牢性の向上
- 設計の一貫性
コメント