nprogram’s blog

気ままに、プログラミングのトピックについて書いていきます

Factory Methodパターン [C#]

Factory Methodパターン

インスタンス化したいオブジェクト(製品)を実行時の条件によって決めたい場合に利用します。
Factory Methodパターンはオブジェクト(製品)を生成する側と利用する側に分けて定義する必要があります。
分けておくことで、将来システムに起こりえる変更をあらかじめ分離でき保守性を保つことができます。

パターン構造

f:id:nprogram:20181116223913p:plain

構成要素

  • Product : 生成されるオブジェクト(製品)のAPIを定義する抽象クラス。製品の具象クラスが抽象クラスで使用できるようにする
  • ConcreteProduct : 生成される具象製品クラス
  • Creator : ファクトリメソッドを除く製品を操作するAPI抽象クラスを定義する抽象クラス
  • ConcreteCreator : ファクトリメソッドを実装し、実際に製品を作成するクラス

クラス図

f:id:nprogram:20181116224953p:plain

コード

using System;

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {

            PizzaStore NYPizzaFactory = new NYPizzaFactory();
            PizzaStore ChicagoPizzaFactory = new ChicagoPizzaFactory();
            
            Pizza pizzaNYCheese = NYPizzaFactory.OrderPizza("Cheese");
            Pizza pizzaNYTomato = NYPizzaFactory.OrderPizza("Tomato");
            Pizza pizzaChicagoCheese = ChicagoPizzaFactory.OrderPizza("Cheese");
            Pizza pizzaChicagoTomato = ChicagoPizzaFactory.OrderPizza("Tomato");
            
            Console.ReadLine();
        }
    }

    /// <summary>
    /// ピザを作成するファクトリークラス (抽象クラス)
    /// </summary>
    public abstract class PizzaStore
    {
        public abstract Pizza CreatePizza(string type);

        public Pizza OrderPizza(string type)
        {
            Pizza pizza;

            pizza = CreatePizza(type);

            if (pizza == null) return null;

            // すべてのピザに対して
            pizza.Prepare();
            pizza.Bake();
            pizza.Cut();
            pizza.Box();

            return pizza;
        }
    }

    /// <summary>
    /// ニューヨークのピザファクトリークラス (具象クラス)
    /// </summary>
    public class NYPizzaFactory : PizzaStore
    {
        public override Pizza CreatePizza(string type)
        {
            Pizza pizza = null;

            if (type == "Cheese")
            {
                pizza = new NYStyleCheesePizza(type);

            }
            else if (type == "Tomato")
            {
                pizza = new NYStyleCheesePizza(type);
            }

            return pizza;
        }
    }

    /// <summary>
    /// シカゴのピザファクトリークラス
    /// </summary>
    public class ChicagoPizzaFactory : PizzaStore
    {
        public override Pizza CreatePizza(string type)
        {
            Pizza pizza = null;

            if (type == "Cheese")
            {
                pizza = new ChicagoStyleCheesePizza(type);

            }
            else if (type == "Tomato")
            {
                pizza = new ChicagoStyleCheesePizza(type);
            }

            return pizza;
        }
    }

    /// <summary>
    /// 抽象Pizzaクラス。
    /// </summary>
    public abstract class Pizza
    {
        /// <summary>
        /// ピザの名前
        /// </summary>
        public string Name;

        /// <summary>
        /// ピザの生地の厚さ
        /// </summary>
        public string Thickness;

        /// <summary>
        /// ピザのチーズ量
        /// </summary>
        public string AmountOfCheese;

        /// <summary>
        /// スタイル
        /// </summary>
        /// <remarks>
        /// ニューヨーク風、シカゴ風など
        /// </remarks>
        public string Style;


        public void Prepare()
        {
            Console.WriteLine(this.Style + "ピザの作成を開始します。");
            Console.WriteLine(this.Name + "ピザの材料を準備します。");
            Console.WriteLine("ピザの生地は" + this.Thickness + "します。");
            Console.WriteLine("チーズ量は" + this.AmountOfCheese + "します。");
        }

        public void Bake()
        {
            Console.WriteLine(this.Name + "ピザを焼きます。");
        }

        public void Cut()
        {
            Console.WriteLine(this.Name + "ピザをカットします。");
        }

        public void Box()
        {
            Console.WriteLine(this.Name + "ピザを箱に収納します。");
            Console.WriteLine();
        }
    }

    /// <summary>
    /// 具象Pizzaクラス (チーズピザ : ニューヨーク風)
    /// </summary>
    public class NYStyleCheesePizza : Pizza
    {
        public NYStyleCheesePizza(string someName)
        {
            this.Name = someName;
            this.Style = "ニューヨーク風";
            this.Thickness = "薄く";
            this.AmountOfCheese = "少なく";
        }
    }

    /// <summary>
    /// 具象Pizzaクラス (トマトピザ : ニューヨーク風)
    /// </summary>
    public class NYStyleTomatoPizza : Pizza
    {

        public NYStyleTomatoPizza(string someName)
        {
            this.Name = someName;
            this.Style = "ニューヨーク風";
            this.Thickness = "薄く";
            this.AmountOfCheese = "少なく";
        }
    }
    /// <summary>
    /// 具象Pizzaクラス (チーズピザ : シカゴ風)
    /// </summary>
    public class ChicagoStyleCheesePizza : Pizza
    {

        public ChicagoStyleCheesePizza(string someName)
        {
            this.Name = someName;
            this.Style = "シカゴ風";
            this.Thickness = "厚く";
            this.AmountOfCheese = "多く";
        }
    }

    /// <summary>
    /// 具象Pizzaクラス (トマトピザ : シカゴ風)
    /// </summary>
    public class ChicagoStyleTomatoPizza : Pizza
    {

        public ChicagoStyleTomatoPizza(string someName)
        {
            this.Name = someName;
            this.Style = "シカゴ風";
            this.Thickness = "厚く";
            this.AmountOfCheese = "多く";
        }
    }
}
ニューヨーク風ピザの作成を開始します。
Cheeseピザの材料を準備します。
ピザの生地は薄くします。
チーズ量は少なくします。
Cheeseピザを焼きます。
Cheeseピザをカットします。
Cheeseピザを箱に収納します。

ニューヨーク風ピザの作成を開始します。
Tomatoピザの材料を準備します。
ピザの生地は薄くします。
チーズ量は少なくします。
Tomatoピザを焼きます。
Tomatoピザをカットします。
Tomatoピザを箱に収納します。

シカゴ風ピザの作成を開始します。
Cheeseピザの材料を準備します。
ピザの生地は厚くします。
チーズ量は多くします。
Cheeseピザを焼きます。
Cheeseピザをカットします。
Cheeseピザを箱に収納します。

シカゴ風ピザの作成を開始します。
Tomatoピザの材料を準備します。
ピザの生地は厚くします。
チーズ量は多くします。
Tomatoピザを焼きます。
Tomatoピザをカットします。
Tomatoピザを箱に収納します。

参考リンク

https://gist.github.com/fujimisakari

事例で学ぶデザインパターン 第 4 回 | オブジェクトの広場