衍生与发展破坏封装,还是违反DRY?

时间:2011-07-01 22:18:23

标签: c++ oop inheritance encapsulation

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

File中获取Sequence是明智之举。它的行为完全相同,但增加了读写文件的功能。 File特定功能很容易实现,无需将Sequence的数据成员标记为受保护。相反,它们可以是私有的,File可以使用Sequence的公共接口。欢乐时光到处都是。

我想创建一个Array类,在内部管理动态分配的内存。 Array对象无法调整大小;大小在构造函数中指定。*

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

从概念上讲,从Sequence派生Array是有意义的。正如FileSequence并具有读取和写入文件的附加功能一样,SequenceArray,具有按需调整大小的附加功能。

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

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

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

什么是最好的举措:推导并潜在破坏封装;使Array成为一个完全独立的课程,并且必须毫无意义地重新实现许多功能;或完全忘记Array并让人们使用Sequence

* 请注意,这是一个充满乐趣和教育的项目,因此具有不可调整大小的动态分配数组的实用性是不可或缺的。

3 个答案:

答案 0 :(得分:4)

您可能会考虑以稍微不同的方向切割问题。也许这个问题可以通过模板解决 - 而不是继承,特别是管理集合缓冲区的策略模板。你有(至少)两个实现:一个用于固定分配,另一个用于自动调整大小。

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

回到继承问题片刻,它归结为:这非常类似于标准圆与椭圆形的情况,其中一个看起来像另一个足够相似,但最终都不满足LSP - 你不能安全地将任何一个视为另一个,所以(至少是公共的)继承是不合适的。私有继承不需要跟随LSP,但通常只在/如果您需要/想要覆盖基类的虚函数时才有用,这似乎也不太可能。

答案 1 :(得分:4)

我不会在这里使用派生。

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

但是,使用Array中的SequenceSequenceArray转发给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 直接转发File是有道理的。 :

Sequence

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

同样,Sequence来自{{1}}是否有意义?您是否有实施问题,例如将{{1}}的内容与磁盘表示同步?

答案 2 :(得分:3)

好吧,在你的情况下从Sequence派生Array 公开继承是绝对坏主意(因为从矩形派生正方形)。在面向对象编程方面,序列不是一个数组,因为Array具有Sequence没有的属性,而且它是:An Array object cannot be resized。如果你进行推导,它将会破坏Liskov substitution principle

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

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