開放閉鎖の原則(Open/Closed Principle)

SOLID原則のひとつ。

開放(Open) 拡張に対して開いている。
閉鎖(Closed) 修正に対して閉じている。

新しく機能を追加するとき、既存のコードを変更せずにあたらしいコードを追加するだけで済むようにする。

格闘家を例にとる

一般的に格闘技には階級がある。
選手は規定の体重以内で計量をパスしなければならない。

public enum WeightClass
{
  Heavy,
  Light
}

public class Fighter
{
  public WeightClass WeightClass;
  public string Name { get; private set; }
  public double Weight { get; set; }

  public Fighter(string name, WeightClass weightClass)
  {
     this.Name = name;
    this.WeightClass = weightClass;
  }

  public bool WeightIn()
  {
    switch (this.WeightClass)
    {
      case WeightClass.Light:
        return this.Weight <= 70.3;
      default:
        return this.Weight <= 120.2;
    }
  }
}

階級を増やす

競技人口の増加により、2階級のみでは競技性が損なわれるため、HeavyとLightの間にMiddleを増やしたい。
WeightClassにMiddleを増やすのは容易(拡張に対して開いている)だが、 WeightInに修正が発生(閉じていない)する。

解決策

格闘家を基底クラスとして、階級ごとに派生クラスを作成する。

public enum WeightClass
{
  Heavy,
  Middle,
  Light
}

public abstract class Fighter
{
  public WeightClass WeightClass;
  public string Name { get; private set; }
  public double Weight { get; set; }

  public Fighter(string name, WeightClass weightClass)
  {
    this.Name = name;
    this.WeightClass = weightClass;
  }

  public abstract bool WeightIn();
}

public class HeavyWeightFighter : Fighter
{
  private static readonly double LIMIT = 120.2;

  public HeavyWeightFighter(string name, WeightClass weightClass) : base(name, weightClass) { }

  public override bool WeightIn() => this.Weight <= LIMIT;
}

public class MiddleWeightFighter : Fighter
{
  private static readonly double LIMIT = 83.9;

  public MiddleWeightFighter(string name, WeightClass weightClass) : base(name, weightClass) { }

  public override bool WeightIn() => this.Weight <= LIMIT;
}

public class LightWeightFighter : Fighter
{
  private static readonly double LIMIT = 70.3;

  public LightWeightFighter(string name, WeightClass weightClass) : base(name, weightClass) { }

  public override bool WeightIn() => this.Weight <= LIMIT;
}