Abstract Factoryパターン

Abstract Facotry

 生成に関するデザインパターン
 整合性が必要とされる一連のオブジェクト群具象クラスを指定することなく生成するインターフェイスを提供する。

整合性が必要とされる一連のオブジェクト

立ち技格闘技を例に考える。
立ち技格闘技といっても、ムエタイシュートボクシング、キックボクシングなどでルールが異なる。
腕を使用した攻撃について、ムエタイの場合は"エルボー"を使えるが、キックボクシングでは使えない。
クリンチ状態の攻撃について、ムエタイの場合は"こかし"を使えるが、キックボクシングでは使えない。
立ち技格闘技の攻撃は共通して、"腕を使用した攻撃", "脚を使用した攻撃", "クリンチ状態の攻撃"に分類した場合、 ムエタイの"腕を使用した攻撃", "脚を使用した攻撃", "クリンチ状態の攻撃"は整合性を保つ必要がある。
この"腕を使用した攻撃", "脚を使用した攻撃", "クリンチ状態の攻撃"が一連のオブジェクト

整合性が取れなくなるパターン

以下のように、立ち技格闘技に対して、"腕を使用した攻撃", "脚を使用した攻撃", "クリンチ状態の攻撃"を個々に設定できるようにした場合、

public class StandingBout
{
    private AbstractLegAttack LegAttack;
    private AbstractHandAttack HandAttack;
    private AbstractClinchWork ClinchWork;
        
    public void SetAbstractLegAttack(AbstractLegAttack abstractLegAttack) => this.LegAttack = abstractLegAttack;
    public void SetAbstractHandAttack(AbstractHandAttack abstractHandAttack) => this.HandAttack = abstractHandAttack;
    public void SetAbstractClinchWork(AbstractClinchWork abstractClinchWork) => this.ClinchWork = abstractClinchWork;
}

 ユーザによっては、"腕を使用した攻撃"にキックボクシング、"クリンチ状態の攻撃"にムエタイなど設定して整合性が取れなくなる可能性がある。

整合性をとる

抽象クラスの立ち技格闘技に各攻撃(一連のオブジェクト)を宣言し、 具象クラス(ムエタイシュートボクシング・キックボクシング)で各攻撃を定義する。

public abstract class AbstractStandingBout
{
    public abstract AbstractLegAttack CreateAbstractLegAttack();
    public abstract AbstractHandAttack CreateAbstractHandAttack();
    public abstract AbstractClinchWork CreateAbstractClinchWork();
}
public class MuayThai : AbstractStandingBout
{
    public override AbstractLegAttack CreateAbstractLegAttack()
        => new MuayThaiLegAttack();

    public override AbstractHandAttack CreateAbstractHandAttack()
        => new MuayThaiHandAttack();

    public override AbstractClinchWork CreateAbstractClinchWork()
        => new MuayThaiClinchWork();
}

 これによって、一連のオブジェクトの整合性は保てる。

具象クラスを指定することなく生成する

これまでのパターンだと以下のように具象クラスを指定することなく生成するは解決できていない。

var standingBout = new MuayThai();

 解決策は、抽象クラスで引数に応じて、具象クラスを作成するメソッドを追加する。

public abstract class AbstractStandingBout
{
    public abstract AbstractLegAttack CreateAbstractLegAttack();
    public abstract AbstractHandAttack CreateAbstractHandAttack();
    public abstract AbstractClinchWork CreateAbstractClinchWork();

    public static AbstractStandingBout CreateAbstractStandingBout(StandingBouts standingBouts)
    {
        return standingBouts switch
        {
            StandingBouts.MuayThai => new MuayThai(),
            StandingBouts.ShootBoxing => new ShootBoxing(),
            _ => new KickBoxing(),
        };
    }
}

クラス図