架构/模式问题 - 隐藏接口背后的实现细节时的问题

时间:2010-12-23 14:13:55

标签: c# .net interface transparency factory

我有几个类BitMask& BitMaskLarge实现了一个接口IBitMask,它公开了执行按位逻辑操作的功能等.BitMask类包含一个long类型的private _mask字段,而BitMaskLarge类包含一个long的私有_masks数组。

最终用户使用IBitMask,每个类的实现细节应该是透明的,例如当两个输入都是一种类型而不是每种类型时,如何实现按位逻辑。

创建IBitMask时,使用BitMaskFactory,根据传递给构造函数的位宽返回相应的类型。

使用SetBitIndex方法在位掩码中设置位时会出现问题。如果该位超出当前掩码的范围,则BitMaskLarge只是向_masks添加另一个元素并设置相应的位。但是BitMask不能超过64位,因此需要转换为BitMaskLarge。显然,在BitMask类上调用bitmask.SetBitIndex(100)时,这是不可能的,它应该在索引100处设置该位。

我能想到的一个可能的解决方案是将SetBitIndex设为内部,并在BitMaskFactory上创建一个返回新的或更新的IBitMask的静态方法。这并不理想,因为它不自然使用。如果有人能更好地解决这个问题,我想听听。无论所需的变化有多么基础,欢迎所有的想法。

6 个答案:

答案 0 :(得分:1)

您可以使实现IBitMask的类型为immutable,并且让变异操作返回一个新实例。这将是这样的:

IBitMask mask = BitMaskFactory(...); // assume mask is now a BitMask
mask = mask.SetBitIndex(100); // now mask is a BitMaskLarge

使实例不可变还可以“免费”提供线程安全。

如果您觉得这很不方便,可以通过添加另一层抽象来解决它:

class BitMaskImplementation : IBitMask {
    private IBitMask mask;

    // BitMaskImplementation defers all operations to mask,
    // and you can change the object stored inside mask without
    // your callers knowing anything about what happened.
}

这会让你失去线程的安全性。

<强>更新

除非BitMaskLargeBitMask贵得多,否则你不应该真正解决所有这些问题,你也希望几乎所有的面具都是简单的BitMask s。

答案 1 :(得分:1)

已描述的BitMask和BitMaskLarge之间的唯一区别是使用_mask vs _masks字段。如果这是真正唯一的区别如何总是从工厂返回BitMaskLarge?在这种情况下你不需要超过一个长,那么你将只在_masks数组中有一个长。

答案 2 :(得分:1)

前端和后端课程怎么样?前端类将为客户端应用程序提供实际的外观(当前由IBitMask接口覆盖的角色)。后端类将提供实际的实现。然后,前端将简单地将来自客户端应用程序的所有调用委托给其内部后端实例,并且如果bitset对于“小”版本变大,则可以透明地替换实现(或者变得足够小以便由“小”表示“版本):

 class BitMask {
     private IBitMaskData actual;
     public void SetBitIndex(int index) {
          actual = actual.SetBitIndex(index);
     }
 }

 // Stuff below is an implementation detail of class BitMask
 // and private

 interface IBitMaskData {
      ...
      IBitMaskData SetBitIndex(int index);
 }

 class SmallBitMask {
      IBitMaskData SetBitIndex(int index) {
          if( index < 64 ) { 
              // Set the bit actually...
              return this;
          } else {
              LargeBitMask newMask = new LargeBitMask(this);
              return newMask.SetBitIndex(index);
          }
      }
 }

 class LargeBitMask {
     ...
 }

(如果你足够关心性能和内存要求来区分大小位掩码,你可能会因为引入了额外的开销而不喜欢这个解决方案)

答案 3 :(得分:0)

您必须决定是否要动态增长位掩码。如果你想要它,那么创建一个支持增长到任意大小的BitMask类。如果你有&lt; = 64位,它仍然可以表现良好,不用担心。否则你必须告诉工厂你想要多大的位掩码,然后你应该禁止设置比类实例更高的索引。

答案 4 :(得分:0)

我个人会说这种情况需要防范 - 因为它是无效的输入。如果您希望能够交换类型,那么您可以在界面上公开ToBitMaskLargeToBitMask方法,以强制实施类管理转换。

当然,这不会自动发生,但它会让你的来电者改变主意而无需重新访问工厂。

答案 5 :(得分:0)

需要考虑两件事:

首先,为什么不能100%只使用BitMaskLarge?如果你说“performace”,我会向你提出差异可以忽略不计。

其次,为什么“升级”到规范的不同类位掩码?您应该将用户限制为返回的IBitMask,或者始终使用“Large”实现。