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