Help us understand the problem. What is going on with this article?

デザインパターン入門_Factory Methond

More than 1 year has passed since last update.

Javaで学ぶデザインパターン入門

結城浩「Javaで学ぶデザインパターン入門」をC#で勉強

FactoryMethod パターン

Templete Methodパターン(スーパークラスで処理の枠組みを定め、 サブクラスでその具体的内容を定めるパターン)をインスタンスの生成場面に 適用したもの。 インスタンス生成のための枠組みとインスタンス生成クラスを分けて考えることができる。

実装 (frameworkパッケージ)

// Productクラス

namespace DesignPatternLearn.FactoryMethodLearn.FrameWork
{
    public abstract class Product
    {
        public abstract void Use();
    }
}

// Factory クラス

namespace DesignPatternLearn.FactoryMethodLearn.FrameWork
{
    public abstract class Factory
    {
        public Product Create(string owner)
        {
            var product = CreateProduct(owner);
            RegisterProduct(product);
            return product;
        }

        public abstract Product CreateProduct(string owner);
        public abstract void RegisterProduct(Product product);

    }
}

実装 (idcardパッケージ)

// IdCardクラス(Productクラスの実装)

using DesignPatternLearn.FactoryMethodLearn.FrameWork;

namespace DesignPatternLearn.FactoryMethodLearn.IdCard
{
    class IDCard : Product
    {
        public string Owner { get; set; }
        public IDCard(string owner)
        {
            Console.WriteLine(owner + "のカードを作ります。");
            this.Owner = owner;
        }
        public override void Use()
        {
            Console.WriteLine(Owner + "のカードを使います。");
        }
    }
}

// IdCardFactoryクラス(Factoryクラスの実装)
using DesignPatternLearn.FactoryMethodLearn.FrameWork;

namespace DesignPatternLearn.FactoryMethodLearn.IdCard
{
    public class IDCardFactory : Factory
    {
        private List<string> owners = new List<string>();
        public List<string> Owners { get => owners; }

        public override Product CreateProduct(string owner)
        {
            return new IDCard(owner);
        }

        public override void RegisterProduct(Product product)
        {
            owners.Add(((IDCard)product).Owner);
        }
    }
}

実装(Main)

using DesignPatternLearn.FactoryMethodLearn.FrameWork;
using DesignPatternLearn.FactoryMethodLearn.IdCard;

namespace DesignPatternLearn.FactoryMethodLearn
{
    class FactoryMethodLearn
    {
        public static void Main(string[] args)
        {
            // Factoryクラス
            Factory factory = new IDCardFactory();

            /* ここが重要
            * インスタンス生成が「new 具体的なクラス名()」ではなく
            * メソッド呼び出しになっている。
            * 違うProductを使いたいとなったときは
            * 呼び出すFactoryクラスさえ切り替えればよく、以下を変更する必要がない
            */
            Product card1 = factory.Create("山田太郎");
            Product card2 = factory.Create("田中太郎");
            Product card3 = factory.Create("佐藤太郎");
            card1.Use();
            card2.Use();
            card3.Use();

            Console.Read();
        }
    }
}

重要な考え方

FlameWorkパッケージがIdCardパッケージに依存していないこと。
→ IdCradパッケージを別のものに切り替えても、FlameWorkパッケージやそれを使用する側の修正が不要。

インスタンス生成方法

Factory Methodパターンを調べていて、便利そうだと思った使い方
→ 条件によって生成するインスタンスを切り替える

/*
* FlameWorkパッケージはそのまま
*/

/*
* Animalパッケージ(上の例のIdCardパッケージに相当)
*/

using DesignPatternLearn.FactoryMethodLearn.FrameWork;
using DesignPatternLearn.FactoryMethodLearn.Animal;

namespace DesignPatternLearn.FactoryMethodLearn
{
    public class AnimalFactory : Factory
    {
        /*
        * この部分
        * 条件によって、作成するインスタンスを切り替える
        */

        public override Product CreateProduct(string owner)
        {
            if (owner.Equals("犬"))
            {
                return new Dog();
            }
            else if (owner.Equals("猫"))
            {
                return new Cat();
            }
            else if (owner.Equals("ネズミ"))
            {
                return new Mouse();
            }

            Console.WriteLine("そんな動物はいないよ");
            return null;
        }

        public override void RegisterProduct(Product product)
        {
            return;
        }
    }
}

using DesignPatternLearn.FactoryMethodLearn.FrameWork;
namespace DesignPatternLearn.FactoryMethodLearn.Animal
{
    public class Dog : Product
    {
        private readonly string cry = "ワン!";
        public string Cry { get => cry;}
        public Dog()
        {
            Console.WriteLine("犬を飼いました。");
        }
        public override void Use()
        {
            Console.WriteLine(Cry);
        }
    }

    public class Cat : Product
    {
        private readonly string cry = "にゃー";
        public string Cry { get => cry; }
        public Cat()
        {
            Console.WriteLine("猫を飼いました。");
        }
        public override void Use()
        {
            Console.WriteLine(Cry);
        }
    }

    public class Mouse : Product
    {
        private readonly string cry = "チュー";
        public string Cry { get => cry; }
        public Mouse()
        {
            Console.WriteLine("ネズミがいます");
        }
        public override void Use()
        {
            Console.WriteLine(Cry);
        }
    }
}

/*
* Mainクラス
*/

using DesignPatternLearn.FactoryMethodLearn.FrameWork;
using DesignPatternLearn.FactoryMethodLearn.IdCard;

namespace DesignPatternLearn.FactoryMethodLearn
{
    class FactoryMethodLearn
    {
        public static void Main(string[] args)
        {
            Factory factory = new AnimalFactory();
            Product card1 = factory.Create("犬");
            Product card2 = factory.Create("猫");
            Product card3 = factory.Create("ネズミ");
            card1.Use();
            card2.Use();
            card3.Use();

            Console.Read();
        }
    }
}

/*
*  ===== 実行結果 =====
*   
*   犬を飼いました。
*   猫を飼いました。
*   ネズミがいます
*   ワン!
*   にゃー
*   チュー
*
*   ====================
*/

dango
学習中。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away