【C++】Factory(デザインパターン)

## Factroyとは?
**オブジェクトの生成処理をカプセル化し、
クライアントコードから具体的なクラス名を隠蔽する**設計。

- 具体的なクラス名を直接記述しないため、**クラス間の結合度を低くできる**
- 新しい種類のオブジェクトを追加する場合、Factoryクラスを修正するだけなので
**柔軟性を向上できる**

### C++
```C++:FactoryMethod.cpp
#include <iostream>
#include <string>
#include <map>
#include <vector>

/// <summary>
/// お祭りの屋台の抽象クラス
/// </summary>
class FestivalShop
{
public:
	/// <summary>
	/// コンストラクタ
	/// </summary>
	/// <param name="_name">店の名前</param>
	FestivalShop(std::string _name)
	{
		name = _name;
	}

	/// <summary>
	/// 名前を取得する
	/// </summary>
	inline std::string GetName(void) const { return name; }

private:
	std::string name;
};

/// <summary>
/// 作成の抽象クラス
/// </summary>
class Creator
{
public:
	inline virtual FestivalShop* Create(void) const = 0;
};

/// <summary>
/// たこ焼き
/// </summary>
class Takoyaki
	: public Creator
{
public:
	inline FestivalShop* Create(void) const override
	{
		return new FestivalShop("たこ焼き");
	}
};

/// <summary>
/// 焼きそば
/// </summary>
class Yakisoba
	: public Creator
{
public:
	inline FestivalShop* Create(void) const override
	{
		return new FestivalShop("焼きそば");
	}
};

/// <summary>
/// チョコバナナ
/// </summary>
class ChocolateBanana
	: public Creator
{
public:
	inline FestivalShop* Create(void) const override
	{
		return new FestivalShop("チョコバナナ");
	}
};

/// <summary>
/// ベビーカステラ
/// </summary>
class BabyCastella
	: public Creator
{
public:
	inline FestivalShop* Create(void) const override
	{
		return new FestivalShop("ベビーカステラ");
	}
};

/// <summary>
/// シングルトン
/// 
/// templateで汎用性強化
/// </summary>
template<typename T>
class Singleton
{
public:
	/// <summary>
	/// デフォルトコンストラクタ
	/// 
	/// コンストラクタは絶対に呼ばない!!
	/// </summary>
	Singleton() {}

	/// <summary>
	/// インスタンスを取得する
	/// </summary>
	static T* GetInstance(void)
	{
		if (instance == nullptr)
		{
			// 初回のみ動的確保
			instance = new T;
		}

		return instance;
	}

	/// <summary>
	/// インスタンスを破棄する
	/// </summary>
	static void DeleteInstance(void)
	{
		// 削除は動的確保している時のみ
		if (instance != nullptr)
		{
			delete instance;
			instance = nullptr;
		}
	}

private:
	static T* instance;
};
template<typename T>
T* Singleton<T>::instance = nullptr;

/// <summary>
/// ファクトリー
/// </summary>
class Factory
	: public Singleton<Factory>
{
public:
	enum class KIND_OF_SHOP
	{
		TAKOYAKI,
		YAKISOBA,
		CHOCOLATE_BANANA,
		BABY_CASTELLA,
	};

	/// <summary>
	/// コンストラクタ
	/// </summary>
	Factory()
	{
		// 生産ラインを登録
		creators[KIND_OF_SHOP::TAKOYAKI] = new Takoyaki();
		creators[KIND_OF_SHOP::YAKISOBA] = new Yakisoba();
		creators[KIND_OF_SHOP::CHOCOLATE_BANANA] = new ChocolateBanana();
		creators[KIND_OF_SHOP::BABY_CASTELLA] = new BabyCastella();
	}

	/// <summary>
	/// デストラクタ
	/// </summary>
	virtual ~Factory()
	{
		// 動的配列の解放
		creators.clear();
	}

	inline FestivalShop* Create(KIND_OF_SHOP key)
	{
		return creators[key]->Create();
	}

private:
	std::map<KIND_OF_SHOP, Creator*> creators;
};

int main(void)
{
	// FestivalShopのポインタをアップキャストして実体を作成
	std::vector<FestivalShop*> festivalShops =
	{
		Factory::GetInstance()->Create(Factory::KIND_OF_SHOP::TAKOYAKI),
		Factory::GetInstance()->Create(Factory::KIND_OF_SHOP::YAKISOBA),
		Factory::GetInstance()->Create(Factory::KIND_OF_SHOP::CHOCOLATE_BANANA),
		Factory::GetInstance()->Create(Factory::KIND_OF_SHOP::BABY_CASTELLA),
	};

	// 出力
	for (auto festivalShop : festivalShops)
	{
		std::cout << festivalShop->GetName() << std::endl;
	}

	// 破棄
	festivalShops.clear();
	Factory::DeleteInstance();

	return 0;
}
```

### C#
```C#:FactoryMethod.cs
using System;
using System.Collections.Generic;

/// <summary>
/// お祭りの屋台の抽象クラス
/// </summary>
public class FestivalShop
{
    private string name;

    /// <summary>
    /// コンストラクタ
    /// </summary>
    /// <param name="_name">店の名前</param>
    public FestivalShop(string _name)
    {
        name = _name;
    }

    /// <summary>
    /// 名前を取得する
    /// </summary>
    public string GetName { get { return name; } }
}

/// <summary>
/// 作成の抽象クラス
/// </summary>
public abstract class Creator
{
    public abstract FestivalShop Create();
}

/// <summary>
/// たこ焼き
/// </summary>
public class Takoyaki : Creator
{
    public override FestivalShop Create()
    {
        return new FestivalShop("たこ焼き");
    }
}

/// <summary>
/// 焼きそば
/// </summary>
public class Yakisoba : Creator
{
    public override FestivalShop Create()
    {
        return new FestivalShop("焼きそば");
    }
}

/// <summary>
/// チョコバナナ
/// </summary>
public class ChocolateBanana : Creator
{
    public override FestivalShop Create()
    {
        return new FestivalShop("チョコバナナ");
    }
}

/// <summary>
/// ベビーカステラ
/// </summary>
public class BabyCastella : Creator
{
    public override FestivalShop Create()
    {
        return new FestivalShop("ベビーカステラ");
    }
}

/// <summary>
/// シングルトン
/// 
/// ジェネリックで汎用性強化
/// where T : new()はインスタンス化の保証
/// </summary>
public class Singleton<T> where T : new()
{
    private static T instance;

    /// <summary>
	/// デフォルトコンストラクタ
	/// 
	/// private化で複製禁止
	/// </summary>
    public Singleton() { }

    /// <summary>
	/// インスタンスを取得する
	/// </summary>
    public static T GetInstance
    {
        get
        {
            // 初回のみ動的確保
            return instance ??= new T();
        }
    }
}

/// <summary>
/// ファクトリー
/// </summary>
public class Factory : Singleton<Factory>
{
    public enum KIND_OF_SHOP
    {
        TAKOYAKI,
		YAKISOBA,
		CHOCOLATE_BANANA,
		BABY_CASTELLA,
	};
    private Dictionary<KIND_OF_SHOP, Creator> creators = new Dictionary<KIND_OF_SHOP, Creator>();

    /// <summary>
    /// コンストラクタ
    /// </summary>
    public Factory()
    {
        // 生産ラインを登録
        creators[KIND_OF_SHOP.TAKOYAKI] = new Takoyaki();
        creators[KIND_OF_SHOP.YAKISOBA] = new Yakisoba();
        creators[KIND_OF_SHOP.CHOCOLATE_BANANA] = new ChocolateBanana();
        creators[KIND_OF_SHOP.BABY_CASTELLA] = new BabyCastella();
    }

    public FestivalShop Create(KIND_OF_SHOP key)
    {
        return creators[key].Create();
    }
};

class Program
{
    static void Main()
    {
        List<FestivalShop> festivalShops = new List<FestivalShop>
        {
            Factory.GetInstance.Create(Factory.KIND_OF_SHOP.TAKOYAKI),
            Factory.GetInstance.Create(Factory.KIND_OF_SHOP.YAKISOBA),
            Factory.GetInstance.Create(Factory.KIND_OF_SHOP.CHOCOLATE_BANANA),
            Factory.GetInstance.Create(Factory.KIND_OF_SHOP.BABY_CASTELLA),
        };

        foreach (FestivalShop festivalShop in festivalShops)
        {
            // 出力
            Console.WriteLine(festivalShop.GetName);
        }
    }
}
```