C#デザインパターン  - FactoryMethod

ここに掲載したコードは、『増補改訂版Java言語で学ぶデザインパターン入門 / 結城 浩(著)』に掲載されているサンプルコードをC#に移植したものです。
解説らしい解説は載せていませんので、『増補改訂版Java言語で学ぶデザインパターン入門 / 結城 浩(著)』も合わせてお読みください。

※当ソースは、Visual C# 2008 Express Editionで動作を確認しています。
  Visual Studio 2005をお使いの方は、ブログの記事を残しておきますので、そちらをご覧ください。



■IProduct.cs
using System;

namespace Gushwell.DesignPatterns.Framework {
    public interface IProduct { 
        void Use();
        // IProductのメンバーに変更(結城氏の意図とは異なる可能性があるが...)
        string Owner { get; }
    }
}


■Factory.cs
using System;
using System.Collections.Generic;

namespace Gushwell.DesignPatterns.Framework {

    public class Factory<T> where T : class, IProduct {
        private List<string> owners = new List<string>();

        // T型のインスタンスを生成する。
        public T Create(string owner) {
            // IProductnの派生クラスにデフォルトコンストラクタを用意し、
            // Ownerを書き込み可のプロパティにすれば、わざわざリフレクションを
            // 使わなくても、以下のコードで良い。
            //   T p = new T();
            //   p.Owner = owner;
            // ただ、そうするとOwnerが読み込み専用のプロパティでなくなってしまう。
            Type t = typeof(T);
            var obj = Activator.CreateInstance(t, owner);
            T p = obj as T;
            RegisterProduct(p);
            return p;
        }

        private void RegisterProduct(T product) {
            owners.Add(product.Owner);
        }

        // Owners は、IEnumerableを返すように変更
        public IEnumerable<string> Owners {
            get { return owners; }
        }
    }
}



■IDCard.cs
using System;
using Gushwell.DesignPatterns.Framework;

namespace Gushwell.DesignPatterns.Concrete {

    public class IDCard : IProduct {
        private string owner;

        public IDCard(string owner) {
            Console.WriteLine("{0} のカードを作ります。", owner);
            this.owner = owner;
        }

        public void Use() {
            Console.WriteLine("{0} のカードを使います。", owner);
        }

        public string Owner {
            get { return owner; }
        }

    }
}




■Program.cs
using System;
using Gushwell.DesignPatterns.Framework;
using Gushwell.DesignPatterns.Concrete;
using Gushwell.Dejavu;

namespace Gushwell.DesignPatterns {
    public class Program {
        public static void Main(string[] args) {
            // Factoryクラスは、IProductを実装していれば、IDCard以外のインスタンスも生成できる
            var factory = new Factory<IDCard>();
            
            // IDCardという具象クラスではなく、IProductというインターフェースに対して
            // プログラミングしている。
            IProduct card1 = factory.Create("結城浩");
            IProduct card2 = factory.Create("とむら");
            IProduct card3 = factory.Create("佐藤花子");
            card1.Use();
            card2.Use();
            card3.Use();

            factory.Owners.ForEach(owner => Console.WriteLine(owner));

        }

    }
}



■EnumerableExtentions.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Gushwell.Dejavu {
    public static class EnumerableExtentions {
        public static void ForEach<T>(this IEnumerable<T> source, Action<T> action) {
            foreach (var x in source) {
                action(x);
            }
        }

        public static void ForEach<T>(this IEnumerable<T> source, Action<T, int> func) {
            int i = 0;
            foreach (var x in source) {
                func(x, i);
                i++;
            }
        }
    }
}