C# に関わらず、プログラムの開発においてコードの再利用性や拡張性を高めるためにデザインパターンを活用することが重要です。
今回は、その中でも「ファクトリーパターン(Factory Pattern)」に焦点を当て、C# での実装手順を紹介します。
ファクトリーパターンは、オブジェクトの生成をカプセル化することで、依存関係の軽減やメンテナンス性の向上を図るためのデザインパターンです。ファクトリーパターンを通じてオブジェクト生成を一元管理することで、同じコードを繰り返し書く必要がなくなります。
この記事ではファクトリーパターンを実装する方法を紹介していますので、ぜひ参考にしてみてください。

オススメの参考書
C#の使い方が丁寧に解説しており、「基礎からしっかりと学びたい」という初心者の方にオススメの一冊です。サンプルコードも記載してあり、各章の最後に復習問題があるので理解度を確認しながら読み進めることができます。新しい C# のバージョンにも対応している書籍です。
ファクトリーパターンとは?

ファクトリーパターンは、オブジェクトの生成をカプセル化することで、依存関係の軽減やメンテナンス性の向上を図るための仕組みです。
オブジェクトの生成をカプセル化するとは、インターフェースに対して、どのオブジェクトを生成するのかを特定のキーワードによって決定するファクトリークラスを提供することを指します。
例えば、ゲーム開発を例にすると、異なる種類のキャラクター(戦士、魔法使い、弓使い)がいる場合、ユーザーが選択したキャラクターによってキャラクターのオブジェクトを生成するファクトリークラスを作成します。戦士を選択した場合は戦士のオブジェクトを生成し、魔法使いを選択した場合は魔法使いのオブジェクトを生成するなど、特定のキーワードで条件分岐させます。
このような仕組みにすることで、生成方法の変更が発生した場合、同じインターフェースを持つ異なるクラスを簡単にファクトリークラスに追加できます。また、オブジェクトを使用するクライアントコードを変更する必要がなく、開発効率の向上が期待できます。
ファクトリーパターン以外のデザインパターンとして、シングルトンがあります。シングルトンの実装方法については以下の記事で詳しく記載しています。

ファクトリーパターンを実装する

ここからはファクトリーパターンを実装する方法を紹介します。
実装のポイント
- インターフェースを利用する
- ファクトリークラスでオブジェクトの生成を分離する
- 分岐条件式を使用して分岐処理を実装する
まずファクトリーパターンで生成するオブジェクトの共通の振る舞いをインターフェースに定義します。
public interface ICharacter
{
// キャラクターの種類
CharacterTypes CharacterType { get; }
// 攻撃
void Attack();
// 防御
void Defense();
}
ここではキャラクターの種類を列挙体に定義しています。後ほど実装するファクトリークラスでは、この列挙体を使用して条件分岐させます。
public enum CharacterTypes
{
Warrir, // 戦士
Magician, // 魔法使い
Archer, // 弓使い
}
次に、インターフェースを継承したクラスを作成します。各クラス毎にプロパティの値を設定したり、メソッドの処理を記述します。
public class WarrirCharacter : ICharacter
{
public CharacterTypes CharacterType { get; }
public WarrirCharacter()
{
CharacterType = CharacterTypes.Archer;
}
public void Attack()
{
Debug.WriteLine("戦士が剣で攻撃した");
}
public void Defense()
{
Debug.WriteLine("戦士が盾で防御した");
}
}
public class MagicianCharacter : ICharacter
{
public CharacterTypes CharacterType { get; }
public MagicianCharacter()
{
CharacterType = CharacterTypes.Magician;
}
public void Attack()
{
Debug.WriteLine("魔法使いが呪文を唱えた");
}
public void Defense()
{
Debug.WriteLine("魔法使いがバリアを張った");
}
}
public class ArcherCharacter : ICharacter
{
public CharacterTypes CharacterType { get; }
public ArcherCharacter()
{
CharacterType = CharacterTypes.Archer;
}
public void Attack()
{
Debug.WriteLine("弓使いが矢を放った");
}
public void Defense()
{
Debug.WriteLine("弓使いが素早く回避した");
}
}
次に、オブジェクトを生成するファクトリークラスを作成します。
基本的にそのクラスがファクトリークラスであることが分かるように、クラスの名前の後ろに「Factory」とサフィックスをつけるといいでしょう。
ここで紹介するサンプルコードではプロジェクト内にファクトリークラスは1つのみのため、static
をつけて静的なクラスとして作成します。
ファクトリークラスは引数を元に生成するオブジェクトを切り替えます。ここでは列挙体であるCharacterTypes
の値によってswitch
式で分岐させます。
以下のswitch
式はC# 9.0以降から利用できる、パターンマッチング時の定数との比較を簡略化して記述しています。
public static class CharacterFactory
{
public static ICharacter CreateCharacter(CharacterTypes characterType)
{
return characterType switch
{
CharacterTypes.Warrir => new WarrirCharacter(),
CharacterTypes.Magician => new MagicianCharacter(),
CharacterTypes.Archer => new ArcherCharacter(),
_ => throw new NotImplementedException(),
};
}
}
これでファクトリークラスの実装は完了です。このコードを使用して実行した例が次になります。
// 作成したインターフェースの型
ICharacter character;
// 戦士を生成
character = CharacterFactory.CreateCharacter(CharacterTypes.Warrir);
Debug.WriteLine($"キャラクターの種類は{character.CharacterType}です");
character.Attack();
character.Defense();
// 魔法使いを生成
character = CharacterFactory.CreateCharacter(CharacterTypes.Magician);
Debug.WriteLine($"キャラクターの種類は{character.CharacterType}です");
character.Attack();
character.Defense();
// 弓使いを生成
character = CharacterFactory.CreateCharacter(CharacterTypes.Archer);
Debug.WriteLine($"キャラクターの種類は{character.CharacterType}です");
character.Attack();
character.Defense();
実行結果は以下のようになります。
キャラクターの種類はArcherです
戦士が剣で攻撃した
戦士が盾で防御した
キャラクターの種類はMagicianです
魔法使いが呪文を唱えた
魔法使いがバリアを張った
キャラクターの種類はArcherです
弓使いが矢を放った
弓使いが素早く回避した
まとめ

この記事では C# でファクトリーパターンを実装する方法について紹介をしました。
ファクトリーパターンを活用すると、依存関係を減らし、コードの保守性を向上させることができます。特に、将来的に新しいクラスが追加することになった場合、クライアントコードを変更せず、ファクトリークラスの変更だけで済む点が大きなメリットです。
ぜひ扱えるようになっておきましょう。



以上、最後まで読んでいただきありがとうございました。