11

我似乎在精神上陷入了享元模式的困境。

首先,假设我有一个一次性类型DisposableFiddle和一个工厂FiddleFactory

public interface DisposableFiddle : IDisposable
{
    // Implements IDisposable
}

public class FiddleFactory
{
    public DisposableFiddle CreateFiddle(SomethingThatDifferentiatesFiddles s)
    {
        // returns a newly created fiddle.
    }
}

然后,在我看来,客户很清楚FiddleFactory工厂声称对创建的小提琴没有所有权,并且客户有责任在处理完小提琴后处理它。

但是,假设我想通过使用享元模式在客户端之间共享小提琴:

public class FiddleFactory
{
    private Dictionary<SomethingThatDifferentiatesFiddles, DisposableFiddle> fiddles = new ...;        

    public DisposableFiddle CreateFiddle(SomethingThatDifferentiatesFiddles s)
    {
        // returns an existing fiddle if a corresponding s is found,
        // or a newly created fiddle, after adding it to the dictionary,
        // if no corresponding s is found.
    }
}

然后我觉得在道德上有义务让工厂本身是一次性的,因为它创造了小提琴并在他们的一生中保持对它们的引用。但这会给假设他们拥有小提琴并因此应该处置它们的客户带来问题。

问题实际上是我调用工厂FiddleFactory而不是,说,FiddlePool和“创建”方法CreateFiddle而不是GetFiddle?像这样:

public class FiddlePool : IDisposable
{
    private Dictionary<SomethingThatDifferentiatesFiddles, DisposableFiddle> fiddles = new ...;        

    public DisposableFiddle GetFiddle(SomethingThatDifferentiatesFiddles s)
    {
        // returns an existing fiddle if a corresponding s is found,
        // or a newly created fiddle, after adding it to the dictionary,
        // if no corresponding s is found.
    }

    // Implements IDisposable
}

然后,客户就更清楚它不会拥有返回的小提琴,并且处理小提琴是池的责任。

还是只能通过文档轻松解决?

有没有办法摆脱困境?甚至有两难境地吗?:-)

4

3 回答 3

7

我可以看到解决这个问题的两种方法:

  • ThreadPool 风格:重新设计类,以便FiddlePool提供一个接口来做一些复杂的事情。池不分发Fiddle实例,因为它有一个FiddlePool.PlayFiddle方法。由于池控制小提琴的生命周期,它负责处理它们。

  • SqlConnection-style:修改Fiddle's public dispose 方法,使其实际上只是将 fiddles 返回到 fiddle 池(fiddle 类封装)。在内部,小提琴池负责真正释放可支配资源。

于 2010-02-25T17:43:58.323 回答
2

我同意你的第二个意见。术语“Pool”和“Get”确实让消费者更清楚。但是,它仍然不够清楚,应始终添加文档以确保完整、有效的理解。

于 2010-02-25T17:39:37.553 回答
1

您应该做的不仅仅是文档和命名方法来告诉客户不要调用 dispose。真的最好让客户调用 dispose 以便使用模式。从我们建立的数据库连接池中获取一些方向。

数据库汇集了一堆连接,这些连接本身是池感知的。调用代码创建一个连接,打开它,然后在它上面调用 close(dispose)。调用代码甚至不知道它是否被池化,它都是由连接类在内部处理的。对于池连接,如果连接已打开,则调用 Open() 将被忽略。调用 Close()/Dispose() 并且在池连接的情况下,这实际上将连接返回到池而不是关闭它。

您可以通过创建一个 PooledFiddle 类来执行相同的操作,该类覆盖 Dispose 并将对象返回到池中。理想情况下,客户甚至不必知道它是一个池化的 Fiddle。

于 2010-02-25T17:49:25.010 回答