如何实施优雅的动物农场?

时间:2014-09-10 13:42:18

标签: c# generics factory

是否有一种优雅的方式(使用泛型和/或激活器和/或任何其他好的技巧)来实现除了大开关之外的对象工厂以用于以下场景?

enum AnimalKind
{
    Bear,
    Fox,
    Ant,
}

abstract class Animal
{
    abstract AnimalKind Kind {get;}
    ...
    static Animal Create(AnimalKind kind) // Factory method, convert kind to animal
    {
        switch (kind)
        {
            case AnimalKind.Bear: return new Bear();
            ...
            // Update this part anytime the new AnimalKind is added
        }
    }
}

class Bear : Animal
{
    override AnimalKind Kind {get {return AnimalKind.Bear;}}
    ...
}
...

不幸的是动物类型是要求,并且所需的目的是在转换之后:List<AnimalKind> => List<Animal>。否则T Create<T>() where T:Animal之类的东西是可能的。由于新动物出现在系统中,代码中的更新越少越好(理想情况是枚举和动物类本身,工厂方法中没有任何内容)。

修改 根据以下评论,最佳答案是here

编辑2:

  • 因为我能够回答被关闭的问题,
  • 由于引用的答案不满足我,
  • 由于对动物农场的反思可能导致表现不佳,
  • 也适用于想要复制/粘贴“工作示例”的人

我在这里发布我的解决方案。随意重新排列和/或改进和/或简化它:

Animal.cs:

using System;
using System.Linq;
using System.Reflection;

namespace ReflectionFactory
{
    public enum AnimalKind
    {
        None,
        Bear,
        Fox, 
        Ant,
    }

    public abstract class Animal
    {
        public const AnimalKind StaticKind = AnimalKind.None;
        public abstract AnimalKind Kind {get;}

        // That is the "trick" I was looking for: kind => Animal, no further changes
        public static Animal Create(AnimalKind kind)
        {
            var asm  = Assembly.GetExecutingAssembly();
            var type = asm.GetTypes()
                          .Where(t => t.IsSubclassOf(typeof(Animal)))
                          .FirstOrDefault(t => (AnimalKind)(t.GetField("StaticKind").GetValue(null)) == kind);

            // FIXME: Might want to check for unwanted type values (like null)

            return (Animal)Activator.CreateInstance(type);
        }
    }

    public class Bear : Animal
    {
        public new const AnimalKind StaticKind = AnimalKind.Bear;
        public override AnimalKind Kind {get{return StaticKind;}}
        // ...
   }

    public class Fox : Animal
    {
        public new const AnimalKind StaticKind = AnimalKind.Fox;
        public override AnimalKind Kind {get{return StaticKind;}}
        // ...
    }

    public class Ant : Animal
    {
        public new const AnimalKind StaticKind = AnimalKind.Ant;
        public override AnimalKind Kind {get{return StaticKind;}}
        // ...
    }
}

Program.cs:

using System;
using System.Collections.Generic;
using System.Linq;

namespace ReflectionFactory
{
    class Program
    {
        static void Main(string[] args)
        {
            var shoppingList = new List<AnimalKind>
            {
                AnimalKind.Bear,
                AnimalKind.Bear,
                AnimalKind.Fox,
                AnimalKind.Ant,
                AnimalKind.Ant,
                AnimalKind.Ant,
            };

            var animalFarm = shoppingList.Select(Animal.Create);

            foreach (var animal in animalFarm)
            {
                Console.WriteLine(animal.Kind);
            }
        }
    }
}

0 个答案:

没有答案
相关问题