我遇到了一个容易解决的但是我年轻时没有遇到过的设计问题。
我有一个课程,在其他任何事情发生之前需要经过一些设置程序。
但是,在构造这个类的过程中,我在构造函数的参数中有一个可以传递的委托,以便用户可以将自己的信息添加到类中。
当调用它时,创建类的作用域仍然没有有效的实例,因此会发生null异常错误。
我该如何设计呢?我应该将“this”的实例传递给该代表吗?
在这里做出什么样的好决定?我有一个“StartServices()”方法,我可以很容易地调用委托,但我觉得它应该在构造函数中设计明智。
感谢您的建议!
答案 0 :(得分:6)
听起来你想传递一个Action<T>
(或类似的),这样无论在哪个阶段想要代表,它都可以调用theDelegate(this)
;例如:
var instance = new SomeType(..., obj => { /* extra code invovling obj */ });
然后obj
将成为创建它的实例,它的优点是编译器生成的方法不需要任何状态/捕获(除非你自己需要)。
然而!我会谨慎地在构造函数中调用委托 ,因为virtual
应该谨慎对待 - 在深层对象模型中,整个类可能无法完全创建触发您的中级构造函数(调用委托或重写方法),提供对处于不完整状态的对象的狡猾访问。
答案 1 :(得分:4)
考虑使用factory method:
public class MyClass
{
private MyClass() {}
public static MyClass Create(delegate d ...)
{
var instance = new MyClass();
d.(instance);
return instance;
}
}
然后像这样使用它:
var o = MyClass.Create(...);
您也可以选择工厂类:
var o = factory.CreateMyClass(...);
答案 2 :(得分:3)
我建议不要在构造函数中使用委托。委托可以轻松访问其他线程上的数据,从而导致几个非明显的副作用。在这种情况下,您应该拆分类创建和类初始化。
使用Factory pattern将帮助您清楚地分离对复杂对象创建的责任,但不能帮助您完成对象初始化。我确实考虑将行为注入构造函数中的反模式。
问题的解决方案可以将行为作为(对象)依赖关系注入定义良好的接口。您希望将代表传递给constroctur,这表明对我的担忧和违反SingelResponsibility原则的分歧很差。
答案 3 :(得分:2)
基本上,听起来你想要的代码根本不应该在构造函数中。构造函数是创建对象的原因。直到它退出对象不能保证“正常工作”。现在,可能工作,是的,你可以得到这个指针,但调用代码会期望它完全构建。因此从设计的角度来看,这不是一个好习惯。只需要在构造函数之后调用另一个方法(如果这有助于你的多态,则使用接口)。
答案 4 :(得分:0)
这种方法看起来很奇怪,代表们做了什么样的设置工作?
也许在构造函数结束时引发一个事件将是一个更标准的方法。