假设我有一个singleton-ish,factory-ish,reflection-ish类接收一些输入,并吐出一个接口的具体实现的新实例。这是什么样的设计?有没有更好的方法来做我想要的?
这里有一些代码来说明这一点:
using System;
using System.Collections.Generic;
// static factory class
public static class ArticleFactory
{
// given an SKU, store the Type object for an IArticle object
private static Dictionary<string, Type> articleRegistry = new Dictionary<string, Type>();
// allow public registration of SKU-to-Type object relationships
public static bool Register(string sku, Type typeInfo)
{
if(!articleRegistry.ContainsKey(sku))
{
articleRegistry.Add(sku, typeInfo);
return true;
}
return false;
}
// given a SKU, give me an instance of the related IArticle object
public static IArticle NewArticle(string sku)
{
if(articleRegistry.ContainsKey(sku))
{
// use reflection to invoke the default constructor
return articleRegistry[sku].GetConstructor(Types.EmptyTypes).Invoke(null) as IArticle;
}
return null;
}
}
// example concrete-implementation of an IArticle
public class Jeans : IArticle
{
public decimal GetPrice() { return SomeDecimal(); }
}
// WHERE DO I CALL THIS LINE?
ArticleFactory.Register("0929-291", typeof(Jeans));
// Later on, if another group needs to write the class for Snowboards,
// how can they self-register their class, without changing any "Main()"
// or "Page_Init()" function?
答案 0 :(得分:2)
看起来你已经确定了这种模式。这是Factory Method Pattern。或者更确切地说,是一个有点半生不熟的实现。稍微好一点的方法是首先使它成为一个接口:
public interface IArticleFactory
{
IArticle CreateArticle(string sku);
}
然后在没有任何反射的情况下实施工厂:
public class MyArticleFactory
{
private Dictionary<string, Func<IArticle>> instantiators =
new Dictionary<string, Func<Iarticle>>();
public MyArticleFactory()
{
Register("Jeans", () => new Jeans());
Register("Shirt", () => new Shirt());
// etc.
}
public IArticle CreateArticle(string sku)
{
Func<IArticle> instantiator;
if (creators.TryGetValue(sku, out instantiator))
return instantiator();
throw new UnknownSkuException(sku);
}
protected void Register(string sku, Func<IArticle> instantiator)
{
creators.Add(sku, instantiator);
}
}
一些重要的差异:
注册不公开,也不应该公开。注册通常要么位于某个配置文件中,要么是私有的。
不要求IArticle
具体类型具有默认的无参数构造函数。这可以很容易地使用参数化构造函数注册文章(只要知道要使用的参数)。
在重复注册时引发异常。我不喜欢简单地回归false
的想法;如果你尝试两次注册相同的工厂方法,那应该被认为是一个错误。
这不是一成不变的。您可以使用其他工厂替换此工厂。你可以对它进行单元测试。
答案 1 :(得分:2)
我不知道它是否有“名称”,但它看起来像某种手动服务解析器。我可以看到的问题(遗憾地来自经验)是它在实际上是不灵活的,因为:
如果我在新系统中这样做,我个人会看一个IoC容器; IoC可以处理这种关系,并提供更多免费功能(生命周期,充实,额外设置等),并解决许多相关问题。
顺便说一句,它可能更容易:return Activator.CreateInstance(articleRegistry[sku]);
答案 2 :(得分:1)
我认为你在这里所做的基本上是依赖注入(或者控制反转就是很酷的孩子所说的)。看看这些链接:
维基百科的解释:http://en.wikipedia.org/wiki/Dependency_Injection
两个DI .Net框架:
StructureMap:http://structuremap.sourceforge.net/QuickStart.htm
Castle Windsor:http://www.castleproject.org/container/index.html
答案 3 :(得分:0)
这只是一个工厂模式,碰巧在其实现中使用反射。但是,不是使用反射,而是简单地将工厂类的实例直接放在字典中可能更有效,尽管这可能需要一些样板代码。