在UML composition聚合中,我倾向于使用IDisposable
接口/模式来强制“ Child
在没有Parent
”的情况下不存在-要求组成要求:
public class Parent : IDisposable
{
private readonly _childs;
public IReadOnlyCollection<Child> Childs => _childs;
public Parent()
{
_childs = new List<Child>();
}
public Child CreateChild()
{
var child = new Child();
_childs.Add(child);
return child;
}
public void Dispose()
{
foreach (var child in _childs)
child.Dispose();
}
}
public class Child : IDisposable
{
internal Child() {}
public void Dispose()
{
//Cleanup object, imagine an idempotent implementation
}
}
到目前为止,太好了。但是现在想象一下这段代码:
var parent = new Parent();
var child = parent.CreateChild();
child.Dispose();
//At this point parent.Childs contains a disposed child object
由于我目前正在开发的图书馆中遇到这种情况,所以我想到了几个问题:
parent.Childs
包含(实际上)不可用的对象吗?
从体系结构的角度来看,主要问题是,IDisposable
对于每个能够获取Child
实例的人都是可见的。隐藏它基本上意味着利用OO多态并将提取处理的能力提取到一个不可见的实现中。但是对于域模型中的许多类来说,这绝对是一个ating肿的因素,而没有其他好处。此外,它固有地将UML组合聚合解释为” {Child
只能 被Parent
” 破坏,我认为这是错误的:
public interface IChild
{
//Child methods
}
internal class Child : IChild, IDisposable
{
//See implementation above
}
public class Parent : IDisposable
{
public IReadOnlyCollection<IChild> Childs => _childs;
public IChild CreateChild()
{
var child = new Child();
_childs.Add(child);
return child;
}
}
答案 0 :(得分:2)
parent.Childs
包含(实际上)不可用的对象可以吗?
是的,但是您永远不要再碰它。通常,处置时触摸ObjectDiposedException
会丢掉它。
我的第一个想法是在处置子对象时使用回调函数/委托将其从活动实例列表中删除,但是对我来说这听起来很笨拙。
笨拙而危险。想象您有一个财务数据集合,突然有些对象因为某些开发人员错误地放置了一个对象而被删除。而是如上所述抛出异常。
剩下的问题是:子对象应该实现IDisposable
,还是应该具有仅父类可以使用的'dispose'方法?这种方法对我来说似乎更有意义。