【发布时间】:2011-11-24 07:48:57
【问题描述】:
通常建议应该密封不可变类,以向消费者强制承诺观察到的类的属性将保持不变。当然,对于将在安全上下文中使用的类来说,这似乎是一个很好的做法。另一方面,在许多情况下,拥有一些具有共同基本特征的不可变类以及这些类的可编辑版本可能会很有用。
例如,一个图形程序可能有一个 DrawnText 对象,它包含一个位置、字体和字符串,以及一个派生的 DrawnFancyText 字符串,它为形状周围的曲线文本添加参数。在某些情况下,拥有这些对象的不可变版本可能很有用(例如,对于诸如撤消缓冲区之类的东西),但在其他情况下,拥有可变版本可能更有用。
在这样的上下文中,有些上下文需要一个可读的 DrawnFancyText 对象,但不关心它是否可变,但有些上下文需要 DrawnText 或 DrawnFancyText 的不可变衍生物,但不关心哪一个。实现前者需要 EditableDrawnFancyText 和 ImmutableDrawnFancyText 有一个共同的基础;实现后者需要 ImmutableDrawnText 和 ImmutableDrawnFancyText 有一个共同的基础。不幸的是,没有多重继承就无法实现这样的模式,因为 ImmutableDrawnText 与 EditableDrawnFancyText 没有关系。幸运的是,即使类不允许,接口也允许多重继承。
似乎实现正确继承关系的最佳方法是定义接口:
- IdrawnText
- IDrawnFancyText:IDrawnText
- IEditableDrawnText:IDrawnText
- IEditableDrawnFancyText:IEditableDrawnText、IDrawnFancyText
- IImmutableDrawnText:IDrawnText
- IImmutableDrawnFancyText:IImmutableDrawnText,IIDrawnFancyText
似乎让类的消费者使用接口而不是类将实现所有正确的对象关系。另一方面,暴露接口意味着消费者必须相信没有人使用允许外部突变的对象实现所谓的“不可变”接口。
对于非安全敏感信息,最好使用接口来允许适当的继承关系,并依靠实现者不违反合同?
理想情况下,可以很好地公开一个公共接口以允许外部实例被传递,而不必允许外部代码定义自己的实现。如果这是可行的,那似乎是最佳方法。不幸的是,虽然可以使用“内部”限定的构造函数公开公共抽象类,但我不知道接口有任何这种能力。不过,我不确定是否有人使用允许外部突变的对象实现“IImmutableDrawnText”一定是一个真正的问题。
编辑 IDrawnText 只会暴露 getter 而不会暴露 setter,但它的文档会明确指出实现 IDrawnText 的对象可能通过其他方式可变,也可能不可变; IImmutableDrawnText 将公开与 IDrawnText 相同的成员,但文档会明确声明允许突变的类禁止实现接口。没有什么可以阻止可变类违反约定实现 IImmutableDrawnText,但任何和所有此类类都将是该接口的破坏实现。
【问题讨论】:
-
不变性与安全性无关。
-
..and 一切与理智有关
标签: c# .net vb.net interface immutability