C Sharp/デザインパターン

出典: フリー教科書『ウィキブックス(Wikibooks)』

デザインパターン[編集]

C#はデザインパターンを実装するための柔軟な言語です。デザインパターンは、ソフトウェア開発における一般的な問題に対する再利用可能な解決策です。C#はこれらのパターンを簡単に実装できるよう設計されており、以下にいくつかの例を挙げます。

Singleton(シングルトン)[編集]

シングルトンパターンは、アプリケーション内で1つのインスタンスしか存在しないようにするためのパターンです。C#での実装には、staticフィールドを持つクラスと、そのクラスのインスタンスを作成するプライベートなコンストラクタを使用します。

using System;

public class Singleton {
  private static Singleton instance;

  private Singleton() {}

  public static Singleton Instance {
    get {
      instance ??= new Singleton();
      return instance;
    }
  }
}

public class Program {
  public static void Main(string[] args) {
    Singleton s1 = Singleton.Instance;
    Singleton s2 = Singleton.Instance;

    Console.WriteLine(s1 == s2); // True: 同一のインスタンスを取得しているか確認
  }
}

このコードは、シングルトン(Singleton)パターンの例です。シングルトンパターンは、特定のクラスがインスタンス化される際に、そのクラスのインスタンスが常に1つだけであることを保証するためのパターンです。

Singletonクラスには、プライベートな静的フィールドinstanceが含まれており、プライベートなコンストラクターが定義されています。このようにすることで、クラスの外部から新しいインスタンスを作成することができません。

Instanceプロパティは、シングルトンのインスタンスを返すために使用されます。最初の呼び出し時にinstancenullである場合、instanceに新しいSingletonインスタンスが代入されます。以降の呼び出しでは、すでに存在するinstanceが返されます。

Mainメソッドでは、Singleton.Instanceを使用して2つのSingletonインスタンスを取得し、それらが同じインスタンスであることを確認するために比較しています。シングルトンパターンでは、複数のインスタンスを取得した場合でも、すべての取得が同じインスタンスを指していることを保証します。そのため、この例ではs1s2は同じインスタンスを参照するため、比較の結果はTrueになります。

Factory Method(ファクトリーメソッド)[編集]

ファクトリーメソッドパターンは、インスタンスの生成をカプセル化するためのパターンです。C#では、ファクトリメソッド、抽象ファクトリ、単純ファクトリなどの構築手法が利用できます。

using System;

public interface IProduct {
  string GetName();
}

public class ConcreteProductA: IProduct {
  public string GetName() => "Product A";
}

public class ConcreteProductB: IProduct {
  public string GetName() => "Product B";
}

public class ProductFactory {
  public IProduct CreateProduct(string type) {
    return type switch {
      "A" => new ConcreteProductA(),
      "B" => new ConcreteProductB(),
      _ => throw new NotSupportedException()
    };
  }
}

class Program {
  static void Main(string[] args) {
    ProductFactory factory = new ProductFactory();

    IProduct productA = factory.CreateProduct("A");
    Console.WriteLine(productA.GetName()); // Output: Product A

    IProduct productB = factory.CreateProduct("B");
    Console.WriteLine(productB.GetName()); // Output: Product B
  }
}

このコードは、ファクトリーパターン(Factory Pattern)の一般的な例です。IProductインターフェースを実装した複数の具象製品クラスを作成し、ProductFactoryクラスを使用してこれらの具象クラスのインスタンスを生成します。

IProductは製品の共通のインターフェースであり、ConcreteProductAConcreteProductBはそれぞれIProductを実装しています。GetName()メソッドはIProductインターフェースに定義されており、各具象クラスではそれぞれ異なる製品名を返します。

ProductFactoryクラスは、与えられたタイプに応じて適切な製品のインスタンスを生成するCreateProduct()メソッドを提供しています。Mainメソッドでは、ProductFactoryを使用して"A"および"B"のタイプの製品を作成し、それぞれの製品の名前を出力しています。

この設計パターンは、新しいオブジェクトを生成する際にクライアントコードから具象クラスの詳細を隠すことができます。代わりに、クライアントはファクトリーメソッドを介して製品のインスタンスを作成し、特定の製品の詳細に依存することなく、インターフェースを通じてそれらの製品を使用できます。

Observer(オブザーバ)[編集]

オブザーバパターンは、オブジェクト間の一対多の依存関係を定義するためのパターンです。C#では、イベントとデリゲートを使用して簡単に実装できます。

using System;

public class Subject {
  public event EventHandler StateChanged;

  private string state;

  public string State {
    get => state;
    set {
      state = value;
      OnStateChanged();
    }
  }

  protected virtual void OnStateChanged() {
    StateChanged?.Invoke(this, EventArgs.Empty);
  }
}

public class Observer {
  public void Subscribe(Subject subject) {
    subject.StateChanged += HandleStateChanged;
  }

  private void HandleStateChanged(object sender, EventArgs e) {
    // Handle the state change
  }
}

class Program {
  static void Main(string[] args) {
    Subject subject = new Subject();
    Observer observer = new Observer();

    observer.Subscribe(subject);

    subject.State = "Updated State"; // This will trigger HandleStateChanged in the Observer
  }
}

このコードは、Observerパターン(観察者パターン)の基本的な実装を示しています。Subject(観察対象)の状態変化を監視し、その変化に応じて何らかのアクションを実行するObserver(観察者)を実装しています。

Subjectクラスは、StateChangedというイベントを持ち、そのイベントが発生した際にOnStateChanged()メソッドを呼び出しています。Observerクラスは、SubjectStateChangedイベントにSubscribeメソッドで登録し、イベントが発生した時にHandleStateChangedメソッドを実行します。

Mainメソッドでは、Subjectインスタンスを作成し、Observerに登録しています。その後、SubjectStateプロパティを変更することで、HandleStateChangedが呼び出されることが期待されます。

これらは、C#で一般的に使用されるデザインパターンの一部です。C#の強力な言語機能を活用して、さまざまなデザインパターンを実装し、ソフトウェアの保守性、再利用性、拡張性を向上させることができます。