假设您有一些工厂创建的资源,在构建之后仍然属于工厂:
public class Resource : IDisposable {
public void Dispose() { /* ... */ }
}
public class ResourceManager : IDisposable {
public Resource Load() { /* create resource and add to list */ }
public void Dispose() { /* dispose all loaded resources in list */ }
}
现在你有一个基类需要在其构造函数中初始化Resource
实例:
public class Fooificator {
public Fooificator(Resource resource) {
this.resource = resource;
}
private Resource resource;
}
如何从这样的基类派生的类构造Resource
而不会丢失对工厂的引用?
使用静态方法的天真方法无法记住工厂(除了丑陋的黑客,比如将它存储在静态字段中,以便构造函数在基类构造完成后获取,或者使用两阶段初始化通过构造函数Resource
方法将Initialize()
赋给基类的地方
public class DefaultFooificator : Fooificator {
public DefaultFooificator() : base(loadDefaultResource()) {}
private static Resource loadDefaultResource() {
ResourceManager resourceManager = new ResourceManager();
return resourceManager.Load();
// Bad: losing reference to ResourceManager here!
}
}
一种可能的解决方法是命名构造函数idiom:
public class DefaultFooificator : Fooificator, IDisposable {
public static DefaultFooificator Create() {
ResourceManager resourceManager = new ResourceManager();
DefaultFooificator fooificator = new DefaultFooificator(
resourceManager.Load()
);
fooificator.resourceManager = resourceManager;
return fooificator;
}
private DefaultFooificator(Resource resource) : base(resource) {}
private ResourceManager resourceManager;
}
但是,在解决存储ResourceManager
引用的问题时,这将不允许从DefaultFooificator
派生更多类。
是否有任何优雅的解决方案可以让我进一步从DefaultFooificator
派生或以其他方式存储ResourceManager
引用?
答案 0 :(得分:1)
为什么派生于Fooificator
的班级应负责构建Resource
?为什么不能将此依赖项注入其构造函数中?
public class DefaultFooificator : Fooificator
{
public DefaultFooificator(Resource resource) : base(resource) {}
}
您可以将资源的创建推迟到FooificatorFactory
。
答案 1 :(得分:1)
我认为你应该考虑你的课程是否紧密耦合。如果Resource具有公共构造函数,则每个人都可以创建一个实例并将其作为对Fooificator构造函数的引用传递。这实际上是件好事。
似乎不太吸引人的是,你似乎要求只能合法地使用ResourceManager.Load创建的资源(BTW,这是违反命令/查询分离)。但是,API不会强制执行此约束。
您应该通过在内部构建资源构造函数或通过解除ResourceManager约束来强制执行此约束。
内部构造函数倾向于拉紧类耦合的方向,所以我认真考虑第二种选择。
或者,更改Fooificator的构造函数以获取对ResourceManager的引用,或者可能是Func<ResourceManager, Resource>
。
如果没有更多的背景,我认为很难给出更好的答案。