如何存储派生类中使用的工厂来初始化其基类?

时间:2009-08-25 10:10:18

标签: c# .net constructor initialization factory

假设您有一些工厂创建的资源,在构建之后仍然属于工厂:

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引用?

2 个答案:

答案 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>

如果没有更多的背景,我认为很难给出更好的答案。