我有一个(不断增长的)数据生成器列表。我需要的生成器是由工厂类创建的。生成器都实现了一个通用接口,其中包括一个静态字符串name
。
我想做什么:使用上述名称的字符串参数调用factory.Create方法。 create方法查找具有此名称的生成器,并返回所述生成器的新实例。
我认为这样做的好处是:我只需添加新的生成器类而无需编辑工厂。
问题:
最后我会像这样称呼工厂(简化):
//Caller
public DataModel GetData2()
{
var generator = new DataFactory().Create("Gen.2");
return generator.GetData();
}
//Factory
public class DataFactory
{
public AbstractDataGenerator Create(string type)
{
//Here the magic happens to find all implementations of IDataGenerator
var allGenerators = GetImplementations();
var generator = allGenerators.FirstOrDefault(f => f.name == type);
if (generator != null)
return (AbstractDataGenerator)Activator.CreateInstance(generator);
else
return null;
}
}
//Interface
public abstract class AbstractDataGenerator
{
public static string name;
public abstract DataModel GetData();
}
//Data-Generators
public class DataGen1 : AbstractDataGenerator
{
public static string name = "Gen.1";
public DataModel GetData()
{
return new DataModel("1");
}
}
public class DataGen2 : AbstractDataGenerator
{
public static string name = "Gen.2";
public DataModel GetData()
{
return new DataModel("2");
}
}
工厂中的魔法GetImplementations()
是应该通过反射完成还是以某种方式不同?我应该采用完全不同的方法吗?
由于答案涉及IoC和DI:该项目已经使用了NInject,因此可以使用。 从接口切换到抽象类。
答案 0 :(得分:4)
这是处理这个问题的好方法吗?
让工厂通过某个键获得你需要的逻辑类的实例 - 我相信这是一个好方法。这是我自己经常使用的一种模式。关于你获得密钥的方式 - 我宁愿不把它作为static
成员(不管接口不能有静态成员),而只是property
并添加IDataGenerator
的基类。该基类将有一个构造函数将获得name
- 这样你创建的每个新DataGenerator
都必须设置它,你不会忘记。
关于将name
作为string
- 我个人更喜欢让它“强烈打字”。我的意思是,如果我用Gen . 2
而不是Gen.2
传递字符串,我将仅在运行时发现此问题。可能的其他方式(如果你想,因为一个简单的字符串也很好 - 一个品味问题):
enum
RequestGenerator
个对象,每个Generator
为IDataGenerator<TGeneratorRequest>
。这可能是一种矫枉过正,但是如果您还需要创建DataGenerator
所需的额外信息,则需要考虑它们。如何找到所有发电机?反映接口的每个实现/命名空间的每个成员(对于生成器及其接口是唯一的)?
是的,反思可能是一种很好的方法。不过,我建议您阅读Dependency Injection
和IoC Containers
,例如Castle Windsor
。有些东西已经为你实现了,所以为什么要重新发明轮子:)
DI
是改变生活的概念
这种工厂工作方式是正确的,还是这种模式不同?
邑。这是一个Factory
工厂中的神奇GetImplementations()是应该通过Reflection完成还是以某种方式不同?
见问题2的答案
答案 1 :(得分:2)
这是构造函数注入可以真正发光的地方。查看依赖注入工具并使用一个!它还会检查您的“奖励”请求。
以下是构造函数注入时工厂的外观:
public class DataFactory
{
private Dictionary<string, IDataGenerator> generators;
public DataFactory(IDataGenerator[] generatorReferences)
{
this.generators = generatorReferences
.ToDictionary(k => k.name, v => v);
}
public IDataGenerator Create(string type)
{
IDataGenerator generator = null;
this.generators.TryGetValue(type, out generator);
return generator;
}
}
大多数DI软件都能够自动扫描程序集以查找特定类型的实现(例如IDataGenerator)并自行注册它们,当它构造一个DataFactory实例时,它会自动包含它们。