WinFormアプリで シンプルなコードからFactoryパターンへ移行しよう

このチュートリアルでは、簡単なオブジェクト生成プログラムを作成し、それをより柔軟で拡張しやすい設計に改善する方法を学びます。まず、シンプルなコードを書き、その後、Factoryパターンというデザインパターンを導入して、コードの設計を改善していきます。

ステップ1: シンプルなコードを作成する

まずは、以下のシンプルなコードを見てください。このコードは、コンボボックスから選択されたアイテムに応じて、対応するオブジェクトを生成し、メッセージを表示するものです。

public partial class Form1 : Form
{
    private Item selectedItem;

    public Form1()
    {
        InitializeComponent();

        comboBox1.Items.Add("剣");
        comboBox1.Items.Add("盾");
        comboBox1.Items.Add("ポーション");

        selectedItem = new Item("剣");  // 初期選択
    }

    private void button1_Click(object sender, EventArgs e)
    {
        switch (comboBox1.SelectedItem.ToString())
        {
            case "剣":
                selectedItem = new Item("剣");
                break;
            case "盾":
                selectedItem = new Item("盾");
                break;
            case "ポーション":
                selectedItem = new Item("ポーション");
                break;
        }

        MessageBox.Show($"選択したアイテム: {selectedItem.Name}");
    }
}
public class Item
{
    public string Name { get; }

    public Item(string name)
    {
        Name = name;
    }
}

このコードはシンプルで理解しやすいですが、アイテムタイプが増えるたびにswitch文を追加する必要があり、コードが複雑になりがちです。

ステップ2: 問題点を理解する

この設計には、以下のような問題があります:

  • コードの一貫性の欠如switch文でアイテムタイプごとに異なる処理を追加するため、メソッドが複数の責任を持ち、肥大化します。
  • 保守性の低下: 新しいアイテムタイプを追加するたびに、Form1クラス内でswitch文に新しいケースを追加する必要があります。
  • 拡張性の問題: 他の部分でも同様のロジックが必要になると、コードの重複が発生する可能性があります。

Factoryパターンの利点

Factoryパターンを導入することで、以下のような改善が見込めます:

  • クラスの責任を分離: アイテム生成の責任をForm1クラスから分離し、独立したファクトリクラスに委譲します。
  • コードの集中化: アイテムの生成ロジックが集中するため、メンテナンスが容易になります。
  • 再利用性の向上: 同じ生成ロジックを他のコンテキストでも再利用可能になります。

ステップ3: Factoryパターンの基本を学ぶ

Factoryパターンとは?

Factoryパターンは、オブジェクトの生成を専用のファクトリクラスに委譲する設計パターンです。これにより、クライアントコードは具体的なクラスの生成方法を知らずに、インスタンスを取得できます。

Factoryパターンの構成

  • インターフェース: 共通のアイテム動作を定義するIItemインターフェースを作成します。
  • 具体的なクラスIItemインターフェースを実装する具体的なアイテムクラス(SwordShieldPotion)を作成します。
  • ファクトリクラス: アイテムの生成を担当するItemFactoryクラスを作成します。

ステップ4: Factoryパターンを適用する

それでは、シンプルなコードをFactoryパターンを使って改善してみましょう。

IItemインターフェースを作成する

まず、アイテムの共通インターフェースを作成します。

public interface IItem
{
    string GetName();
}

具体的なアイテムクラスを別ファイルで作成する

次に、IItemインターフェースを実装する具体的なアイテムクラスを作成します。

Sword.cs

public class Sword : IItem
{
    public string GetName()
    {
        return "剣";
    }
}

Shield.cs

public class Shield : IItem
{
    public string GetName()
    {
        return "盾";
    }
}

Potion.cs

public class Potion : IItem
{
    public string GetName()
    {
        return "ポーション";
    }
}

ItemFactoryクラスを作成する

次に、ItemFactoryクラスを作成して、アイテムの生成を担当させます。

public static class ItemFactory
{
    public static IItem CreateItem(string itemType)
    {
        return itemType switch
        {
            "剣" => new Sword(),
            "盾" => new Shield(),
            "ポーション" => new Potion(),
            _ => throw new ArgumentException("無効なアイテムタイプ"),
        };
    }
}
public static class ItemFactory
{
    public static IItem CreateItem(string itemType)
    {
        switch (itemType)
        {
            case "剣":
                return new Sword();
            case "盾":
                return new Shield();
            case "ポーション":
                return new Potion();
            default:
                throw new ArgumentException("無効なアイテムタイプ");
        }
    }
}

Form1クラスを更新する

最後に、Form1クラスをFactoryパターンに合わせて更新します。

public partial class Form1 : Form
{
    private IItem selectedItem;

    public Form1()
    {
        InitializeComponent();

        comboBox1.Items.Add("剣");
        comboBox1.Items.Add("盾");
        comboBox1.Items.Add("ポーション");

        selectedItem = ItemFactory.CreateItem("剣");
    }

    private void button1_Click(object sender, EventArgs e)
    {
        selectedItem = ItemFactory.CreateItem(comboBox1.SelectedItem.ToString());
        MessageBox.Show($"選択したアイテム: {selectedItem.GetName()}");
    }
}

ステップ5: 振り返りと応用

振り返り

  • 柔軟な設計: 新しいアイテムを追加する際も、ItemFactoryに新しいクラスを登録するだけで済むため、柔軟な設計が可能です。
  • コードの分離: アイテム生成のロジックがItemFactoryに集中しており、メンテナンスがしやすくなりました。

応用例

Factoryパターンは、オブジェクトの生成が複雑になるシナリオや、生成するクラスが動的に決定される場面で非常に有効です。例えば、データベース接続やUIコンポーネントの生成にも応用できます。

このチュートリアルを通じて、シンプルな設計からデザインパターンを導入するプロセスを学び、より柔軟で拡張性のあるコードを書けるようになりましょう。


このように、Factoryパターンの導入によって、シンプルなコードがどのように改善されるかを学ぶことができます。