2012-02-21 93 views
1

我发现我的设计是错误的,并问你如何解决我的问题。工厂方法构造函数的类型约束

所以我的情况:

我写的工厂方法,上课,巫婆从我的特殊基类派生。所以我写了

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

接口不能containts构造 – Yavanosta 2012-02-21 20:07:38

回答

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

+0

有两个坏的地方这样说: 1.思考是真的expencive和缓慢 2.如果程序员使用工厂错误的类,或工厂将无法选择构造器,这将是运行时错误,但在编译时控制类型安全性要好得多。 – Yavanosta 2012-02-21 20:04:22

+0

@Yavanosta在性能方面,很多反思不好的说唱来自早期版本的框架。它在最近的版本中已经有所优化。尽管如此,它还是比较慢。当然,编译时检查会很好。但是唯一的方法就是使用'new()'约束,正如你注意到的那样,如果你需要一个参数化的构造函数,这是没有帮助的。有关更多想法,请参阅编辑答案。 – phoog 2012-02-21 20:11:15

+0

@Yavanosta我再次编辑更多的想法。 – phoog 2012-02-21 20:17:25

2

对于IoC容器听起来像是一个问题。如果您的工厂使用了像StructureMap或Unity这样的容器,那么您的构造函数问题将不再成为问题。工厂会要求StructureMap(例如)解析MyBaseClass,并且它会使用最贪婪的构造函数返回MyBaseClass的实例,递归地构建它的所有依赖关系等等。

1

构造函数不是继承的,也不允许在接口上使用。这意味着每个类的构造函数都只针对该类。这也意味着一个子类可以由你的基类构成,它没有一个与你的模式匹配的构造函数。如果你想有一个标准的配置对象的方式,我认为你的基类上的abstract Init(foo, bar, baz)与你的想法类似,是最好的解决方案。如果对象在被初始化之前被访问,你也可以实现内部逻辑,但不幸的是,你不能在编译时强制执行它。

相关问题