我发现我的设计错了,并问你如何解决我的问题。
所以我的情况:
我正在编写工厂方法,对于类,女巫来自我的特殊基类。所以我写了
public T MyFactory<T>() where T:MyBaseClass
但我的工厂方法的主要工作是获取一些特殊参数并将其传递给新对象的构造函数。 MyBaseClass
有这个构造函数:
public MyBaseClass(MySpecParam param){...}
但无法保证从T
派生的MyBaseClass
类型具有此类构造函数。
我看到的唯一解决方案是将new()
约束和虚拟Init
方法添加到MyBaseClass
,以便工厂可以安全地创建T
类型的新对象,然后使用MySpecParam
对象初始化它。
但是,MyBaseClass
有这样的设计,所以如果它不是MySpecParam
,它就完全无法使用。并且用户可以使用无参数构造函数创建MyBaseClass
并获得完全无效但未初始化的对象。我认为这不好。
无法添加new(MySpecParam)
约束。
我如何设计我的对象,构造函数和工厂方法?
答案 0 :(得分:2)
如果每个类只有一个公共构造函数,你可以通过反射找到它,确定它需要什么参数,并在调用构造函数时提供适当的值(仍然通过反射)。
否则,我认为你有一组有限的构造函数签名。在这种情况下,您需要某种方法来确定要调用的构造函数;该决定可能部分基于类型参数T
的身份。
修改强>
如果您不愿意因评论中列出的原因而使用反思,那么答案或多或少是“不,您不能这样做”。 Michael Yoon提出了一个IoC框架,它当然使用反射并且也会受到运行时错误的影响。根据我的经验(使用Castle Windsor),性能从来就不是问题,并且由于配置错误导致的运行时错误几乎立即在开发周期中被捕获。
另一个想法;这可能没有帮助,但可能值得考虑。您可以使用Func<T>
创建实例,甚至可以为不同类型的Func<T, TOut>
,Func<T1, T2, TOut>
等设置工厂方法的重载,您可以在其中调用
var obj = FactoryMethod<SomeType>(() => new SomeType(23));
或者,考虑abstract factory pattern。
答案 1 :(得分:2)
对于IoC容器来说,这听起来像是一个问题。如果您的工厂使用了像StructureMap或Unity这样的容器,那么您的构造函数问题将不再是一个问题。工厂会要求StructureMap(例如)解析MyBaseClass,它会使用最贪婪的构造函数返回一个MyBaseClass实例,递归地构建所有依赖项等等。
答案 2 :(得分:1)
构造函数不是继承的,也不允许在接口上使用。这意味着每个类的构造函数仅特定于该类。这也意味着子类可以由您的基类组成,该基类没有与您的模式匹配的构造函数。如果您想要一种标准的配置对象的方法,我认为基类上的abstract Init(foo, bar, baz)
与您的想法类似,是最佳解决方案。如果在初始化对象之前访问对象,您还可以实现内部逻辑,但不幸的是,您将无法在编译时强制执行该操作。