1
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

SOLID原則まとめ (C#サンプルコード付き)

Last updated at Posted at 2025-02-21

はじめに

SOLID原則とは、オブジェクト指向設計において、保守性や拡張性を高めるための5つの基本原則になります。

  1. 単一責任の原則(Single Responsibility Principle: SRP)
  2. 開放/閉鎖の原則(Open/Closed Principle: OCP)
  3. リスコフの置換原則(Liskov Substitution Principle: LSP)
  4. インターフェース分離の原則(Interface Segregation Principle: ISP)
  5. 依存関係逆転の原則(Dependency Inversion Principle: DIP)

1. 単一責任の原則(SRP)

~クラスは1つの責務(役割)のみを持つべき~

悪い例

public class Player
{
    public void Move() {
        Console.WriteLine("プレイヤーが移動しました。");
    }
    
    public void Attack() {
        Console.WriteLine("プレイヤーが攻撃しました。");
    }
    
    public void SavePlayerData() {
        Console.WriteLine("プレイヤーデータを保存しました。");
    }
}

このクラスは移動・攻撃・データの保存という異なる責務を持っており、責務が混在しています。

良い例

public class Player
{
    public void Move() {
        Console.WriteLine("プレイヤーが移動しました。");
    }
    
    public void Attack() {
        Console.WriteLine("プレイヤーが攻撃しました。");
    }
}

public class PlayerDataSaver
{
    public void Save(Player player) {
        Console.WriteLine("プレイヤーデータを保存しました。");
    }
}

責務を分けることで、変更に強い設計になります。

2. 開放/閉鎖の原則(OCP)

~クラスは拡張に対して開いており、修正に対して閉じているべき~

悪い例

public class Enemy
{
    public void Attack(string type)
    {
        if (type == "Goblin")
            Console.WriteLine("ゴブリンが噛みついた!");
        else if (type == "Dragon")
            Console.WriteLine("ドラゴンが火を吹いた!");
    }
}

敵の種類が増えるたびに、既存コード(Attackメソッド)を修正する必要があます。

良い例

public interface IEnemy
{
    void Attack();
}

public class Goblin : IEnemy
{
    public void Attack() => Console.WriteLine("ゴブリンが噛みついた!");
}

public class Dragon : IEnemy
{
    public void Attack() => Console.WriteLine("ドラゴンが火を吹いた!");
}

public class EnemyAttacker
{
    public void AttackEnemy(IEnemy enemy)
    {
        enemy.Attack();
    }
}

新しい敵を追加する際に、既存のコードを変更せずに拡張できます。

3. リスコフの置換原則(LSP)

~派生クラスは基底クラスの代替として機能すべき~

悪い例

public class Character
{
    public virtual void Attack() {
        Console.WriteLine("キャラクターが攻撃!");
    }
}

public class Healer : Character
{
    public override void Attack() {
        throw new NotImplementedException("ヒーラーは攻撃できません。");
    }
}

Character 型として扱うと、Healer クラスで例外が発生します。派生クラスが基底クラスの動作を破壊しています。

良い例

public interface ICharacter
{
    void PerformAction();
}

public class Warrior : ICharacter
{
    public void PerformAction() => Console.WriteLine("戦士が攻撃!");
}

public class Healer : ICharacter
{
    public void PerformAction() => Console.WriteLine("ヒーラーが回復!");
}

キャラクターの行動を PerformAction に統一し、期待通りの振る舞いを保証します。

4. インターフェース分離の原則(ISP)

~クライアントは使用しないメソッドに依存してはならない~

悪い例

public interface ICharacter
{
    void Attack();
    void Heal();
}

public class Warrior : ICharacter
{
    public void Attack() => Console.WriteLine("戦士が攻撃!");
    public void Heal() => throw new NotImplementedException();
}

戦士は回復できないにも関わらず、無関係なメソッド(Healメソッド)の実装を強制されてしまっています。

良い例

public interface IAttacker
{
    void Attack();
}

public interface IHealer
{
    void Heal();
}

public class Warrior : IAttacker
{
    public void Attack() => Console.WriteLine("戦士が攻撃!");
}

public class Priest : IHealer
{
    public void Heal() => Console.WriteLine("僧侶が回復!");
}

不必要なメソッドの強制を避け、適切に分離できます。

5. 依存関係逆転の原則(DIP)

~高レベルモジュールは低レベルモジュールに依存してはならない~

悪い例

public class Sword
{
    public void Use() => Console.WriteLine("剣を振った!");
}

public class Player
{
    private Sword _weapon = new Sword();
    public void Attack() => _weapon.Use();
}

Player クラスは 具体的な実装(Sword)に直接依存しており、拡張性が低くなっています。

良い例

public interface IWeapon
{
    void Use();
}

public class Sword : IWeapon
{
    public void Use() => Console.WriteLine("剣を振った!");
}

public class Player
{
    private readonly IWeapon _weapon;
    public Player(IWeapon weapon) => _weapon = weapon;
    public void Attack() => _weapon.Use();
}

IWeapon インターフェースを導入することで、拡張性が向上します。

1
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?