如果安全性不是问题,那么一个不可变的接口是一个好的模式吗?

sup*_*cat 2 .net c# vb.net interface immutability

通常建议应该密封不可变类,以强制向消费者承诺观察到的类的属性将保持不变.当然,对于将在安全环境中使用的类来说,这似乎是一种很好的做法.另一方面,在许多情况下,拥有许多具有共同基本特征的不可变类可能是有用的,并且还具有这种类的可编辑版本.

例如,图形程序可能有一个包含位置,字体和字符串的DrawnText对象,以及一个衍生的DrawnFancyText字符串,它将参数添加到形状周围的曲线文本中.在某些上下文中使用这些对象的不可变版本(例如,对于诸如撤消缓冲区之类的东西)可能是有用的,但在其他上下文中,具有可变版本可能更有用.

在这样的上下文中,有一些上下文需要一个可读的DrawnFancyText对象,但不关心它是否可变,但是还有一些上下文需要一个不可变的衍生文件:DrawnText或者DrawFancyText,但不关心哪个.实现前者需要EditableDrawnFancyText和ImmutableDrawnFancyText具有共同基础; 实现后者需要ImmutableDrawnText和ImmutableDrawnFancyText具有共同基础.遗憾的是,如果没有多重继承,就无法实现这样的模式,因为ImmutableDrawnText与EditableDrawnFancyText没有任何关系.幸运的是,接口确实允许多重继承,即使类没有.

看来,实现正确的继承关系的最佳方法是定义接口:

  1. IDrawnText
  2. IDrawnFancyText:IDrawnText
  3. IEditableDrawnText:IDrawnText
  4. IEditableDrawnFancyText:IEditableDrawnText,IDrawnFancyText
  5. IImmutableDrawnText:IDrawnText
  6. IImmutableDrawnFancyText:IImmutableDrawnText,IIDrawnFancyText

看起来让类的使用者使用接口而不是类会实现所有正确的对象关系.另一方面,暴露接口意味着消费者必须相信没有人实现所谓的"不可变"接口与允许外部突变的对象.

对于非安全敏感信息,使用接口是否合适以便允许正确的继承关系,并依赖实现者不违反合同?

理想情况下,可以充分公开公共接口以允许传递外部实例,而不必允许外部代码定义自己的实现.如果这是可行的,那似乎是最佳方法.不幸的是,虽然可以使用"内部"限定的构造函数公开公共抽象类,但我不知道任何这样的接口能力.尽管如此,我不确定是否有人使用允许外部突变的对象实现"IImmutableDrawnText"必然是一个真正的问题.

编辑 IDrawnText只会暴露getter而不是setter,但是它的文档会明确声明实现IDrawnText的对象可能通过其他方式可变,也可能不可变; IImmutableDrawnText将公开与IDrawnText相同的成员,但文档将明确声明禁止允许变异的类实现接口.什么都不会阻止可变类违反合同实现IImmutableDrawnText,但任何和所有这样的类都将是该接口的破坏实现.

cHa*_*Hao 6

没有"不可变的界面"这样的东西.有一个接口不会声明改变对象的方法,但没有办法禁止变异.允许变异允许所有线程安全和"安全"问题随之而来.

不可变类应该被密封的原因是它们做出了承诺,即一旦创建它们就不能(通常)被修改.子类可以破坏该承诺(和LSP一起),禁止继承是强制执行承诺的唯一方法.

顺便说一句,不变性不是为了安全.允许反射的语言/框架(比如C#/ .net?)可用于虚拟地随意修改对象,忽略对象为防止它而做的所有事情.不变性主要是因为偶然难以做到.