はじめに
この記事では、良い依存と悪い依存を見分ける方法と、設計に役立つ依存性の逆転の原則について解説します。
この記事でわかること
- 良い依存と悪い依存の区別ができる
- 依存性の逆転の原則を理解し、柔軟で保守性の高い設計ができる
対象読者
- 設計をこれから学びたい人
- 「依存は良くない」と言われてもピンと来ない人
依存とは?
クラス間の依存
「依存」とは、クラスが他のクラスを直接参照している状態を指します。以下のコードを例に説明します。
public class ObjectA
{
public void Client()
{
ObjectB objectB = new ObjectB(); // ここが依存
objectB.Log();
}
}
public class ObjectB
{
public void Log()
{
Console.WriteLine("Hello, World!");
}
}
このコードのポイント:
-
ObjectA
がObjectB
を直接参照し、Log
メソッドを呼び出しています。 - この依存によって、
ObjectB
の変更がObjectA
に影響を与えます。
依存の安定度と柔軟性
安定度とは?
依存には安定度と柔軟性がトレードオフの関係で存在します。
以下の例を見てみましょう。
public class ObjectA
{
public void Client()
{
ObjectB objectB = new ObjectB(); // ここが依存
objectB.Log(); // ここでエラーが発生
}
}
public class ObjectB
{
public void Log(string name) // ここでメソッド定義を変更
{
Console.WriteLine($"{name}さんこんにちは。");
}
}
変更が引き起こす影響
-
ObjectB
を変更すると、ObjectA
が影響を受けます。このように、依存先が変化すると依存元にも影響が波及します。 - 一方で、
ObjectA
が変更されても、ObjectB
には影響がありません。
安定度の指針
変更されにくいもの(=安定しているもの)に依存するのが基本です。しかし、依存方向を常に変更されにくいものに向けるのは難しい場合もあります。そこで登場するのが依存性の逆転の原則です。
依存性の逆転の原則
原則の概要
依存性の逆転の原則(DIP: Dependency Inversion Principle)とは、
「変化しやすい具象クラスではなく、抽象に依存する設計にすることで、変更の影響を最小限に抑える」
という考え方です。
以下のコードで、依存性の逆転を適用した例を見てみましょう。
public class ObjectA
{
public void Client()
{
IAdapter adapter = new ObjectB(); // 抽象に依存
adapter.Log("山田");
}
}
public class ObjectB : IAdapter
{
public void Log(string name)
{
Console.WriteLine($"{name}さんこんにちは。");
}
}
public interface IAdapter
{
void Log(string name);
}
この設計のメリット
-
ObjectA
はIAdapter
(抽象)に依存しているため、ObjectB
の具体的な実装変更に影響を受けません。 - もし他の
ObjectC
を新たに追加した場合でも、IAdapter
を実装するだけでObjectA
のコードに変更は不要です。
クラス図で理解する
この構造をクラス図に表すと、次のようになります:
ObjectA → IAdapter ← ObjectB
- 依存の方向性が「抽象」に向いているため、柔軟性が高く、変更に強い設計です。
まとめ
依存性の逆転の原則のポイント
- 具象ではなく抽象に依存することで、変更に強い設計を実現する。
- 変更しやすい部分を隠蔽し、クラス間の独立性を高める。