我似乎在精神上处于Flyweight模式困境中。
首先,假设我有一次性类型DisposableFiddle
和工厂FiddleFactory
:
public interface DisposableFiddle : IDisposable
{
// Implements IDisposable
}
public class FiddleFactory
{
public DisposableFiddle CreateFiddle(SomethingThatDifferentiatesFiddles s)
{
// returns a newly created fiddle.
}
}
然后,在我看来,FiddleFactory
的客户很清楚,工厂声称没有创建小提琴的所有权,并且在完成操作时,客户有责任处置小提琴。
但是,让我们说我想通过使用Flyweight模式在客户端之间分享小提琴:
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
}
然后对客户来说更清楚的是它不会拥有返回的小提琴,并且游泳池有责任处理小提琴。
或者这只能在文档方面轻松解决吗?
有没有摆脱困境的方法?甚至有两难吗? : - )
答案 0 :(得分:7)
我可以看到解决这个问题的两种方法:
ThreadPool风格:重新设计类,以便FiddlePool
提供一个界面来做繁琐的事情。该池不会分发Fiddle
个实例,因为它具有FiddlePool.PlayFiddle
方法。由于游泳池控制着生命周期,因此它负责处理它们。
SqlConnection-style :修改Fiddle
的公共配置方法,以便它真正只是将小提琴返回到小提琴池(小提琴类封装)。在内部,小提琴池负责真正释放可支配资源。
答案 1 :(得分:2)
我同意你的第二意见。术语“池”和“获取”确实使消费者更清楚。但是,它仍然没有说清楚,并且应该始终添加文档以确保完整,有效的理解。
答案 2 :(得分:1)
您应该做的不仅仅是文档和命名方法,以告诉客户不要调用dispose。真的,最好让客户端调用dispose,以便使用该模式。从我们的数据库连接池中建立一些方向。
数据库汇集了一堆本身可以识别池的连接。调用代码会创建一个连接,打开它,并在其上调用close(dispose)。调用代码甚至不知道它是否合并,它都是由连接类在内部处理的。使用池连接,如果连接已打开,则忽略调用Open()。调用Close()/ Dispose(),并且在池连接的情况下,这实际上会将连接返回到池而不是关闭它。
您可以通过创建一个PooledFiddle类来执行相同的操作,该类重写Dispose并将对象返回到池中。理想情况下,客户甚至不必知道它是一个汇集的小提琴。