繁体   English   中英

导出和销毁封装,还是违反 DRY?

[英]Derive & Destroy Encapsulation, or Violate DRY?

我有两个 C++ 类: Sequence ,就像std::vectorFile ,它是代表机器上文件的字符串Sequence

Sequence派生File是不费吹灰之力的。 它的行为完全相同,但增加了读取和写入文件的功能。 File特定的功能很容易实现,无需将Sequence的数据成员标记为受保护。 相反,它们可以是私有的,并且File可以使用Sequence的公共接口。 到处都是快乐的时光。

我想制作一个内部管理动态分配的 memory 的Array class。 无法调整Array object 的大小; 大小在构造函数中指定。*

这就是事情变得有争议的地方。

从概念上讲,从Array派生Sequence是有意义的。 就像File是一个具有读取和写入文件的附加功能的Sequence Sequence一个具有按需调整大小的附加功能的Array

但有一个关键区别:调整大小功能需要直接访问正在管理的 memory Array 换句话说,以前的私有成员现在必须受到保护。

使用受保护成员而不是私有成员会破坏封装。 ArraySequence之间的链接是唯一需要它的链接; 作品中的其他类可以只使用它们父母的公共接口。 从这个意义上说,推导是个坏主意。

您可能会争辩说,想要 arrays 的人可以只使用Sequence并忽略调整大小的功能。 但是话又说回来,您可以只使用File并忽略读/写功能。 这就像购买一台笔记本电脑,但从未将其从办公桌上移开。 这根本没有意义。

最好的举措是什么:派生并可能破坏封装; 使Array成为一个完全独立的 class,并且必须毫无意义地重新实现很多功能; 还是完全忘记Array而只是让人们使用Sequence

*请注意,这是一个娱乐和教育项目,因此具有不可调整大小的动态分配数组的实用性无关紧要。

您可能会考虑将问题切入稍微不同的方向。 而不是 inheritance,也许这个问题可以用一个模板来解决——具体来说,一个管理集合缓冲区的策略模板。 您将拥有(至少)两种实现方式:一种用于固定分配,另一种用于自动调整大小。

这根本不会破坏封装,而且我可以看到两者之间几乎唯一的重叠是初始分配可能大致相同,无论是固定的还是可变的。 鉴于这是多么微不足道,我怀疑是否值得花费大量时间或精力来尝试将其排除在外。 理论上可能是这样,但至少在典型情况下,我们谈论的是一行代码,而且是非常简单的一行代码。

暂时回到 inheritance 问题,归结为:这非常类似于标准圆形与椭圆形的情况,其中一个看起来像另一个,但最终两者都不满足 LSP - 你不能安全地将任何一个视为另一个,因此(至少是公开的)inheritance 不适合。 私有 inheritance 不需要遵循 LSP,但通常仅在/如果您需要/想要覆盖基类的虚拟 function 时有用,这在这里似乎也不太可能。

我不会在这里使用推导。

Sequence并不是真正的Array 虽然实际上它们似乎有许多常用方法,但从设计的角度来看,它们有非常不同的用途和保证。

但是,在Sequence中使用Array并让Sequence直接将多个调用(内联)转发到Array是有意义的:

template <typename T>
class Sequence
{
public:
  Sequence(): _array(10) {}
  explicit Sequence(size_t n): _array(n) {}

  bool empty() const { return _size == 0; }
  size_t size() const { return _size; }
  size_t capacity() const { return _array.size(); }

private:
  size_t _size; // current size
  Array<T> _array;
}; // class Sequence

注意:我在这里假设 Array 是同时使用其所有元素构建的,而序列将一次添加一个

同样, FileSequence派生是否有意义? 您是否没有实现问题,例如将Sequence的内容与磁盘表示同步?

好吧,在您的情况下,使用公共inheritance 从Array派生Sequence绝对是个坏主意(从矩形派生正方形)。 就面向对象编程而言,Sequence IS NOT an Array,因为Array具有Sequence所没有的属性,它是: An Array object cannot be resized 如果进行推导,就会破坏Liskov 替换原则

在您的情况下,由于您想要实现一些功能,已经存在于另一个 class 中,我建议您使用私有inheritance (这意味着 inheritance 的实现),或存储Sequence的私有区域组合和例如Array将其用于内部实现。

UPD:但是,在我看来,使用Array实现Sequence也很成问题。 也许最好创建一些抽象的基础 class Container来实现SequenceArray的通用功能,然后从中派生这两个类。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM