C++ 类层次结构的设计方法学

关于 C++ 类层次结构的设计方法学,note-to-self + keynote + cross-reference 式笔记

本文精炼于 [CPP LANG] 12.4, 15.2 的 BBWindow 示例,只涉及 design
Syntax 参考 [CPP LANG] Ch12, 15; [CPP PRIMER] Ch17, 18
Play with bits 参考 [CPP OBJMODEL] 5.2

keyword: class hierarchy, multiple inheritance, abstract class, virtual base class, abstract factory, clone

目录

示例场景 分离实现和接口 替换实现 重复基类 共享实现 抽象工厂 Clone 模式 示例场景^

IValBox: 取得用户输入整数的 GUI 元素之抽象类,它不绑定具体 GUI 元素,如 slider 滑块, dial 拨盘

IValSlider: 滑块式 IValBox 实现,类似的还有 IValDial 拨盘式实现,代表 IValBox 类层次中具体的 GUI 元素。这些类可以进一步扩展,如从 IValSlider 派生出 PopupIValSlider

BBWindow: 第三方提供的 GUI 元素实现,类似 MFC 的 CWnd 等。IValBox 的类层次依靠 BBWindow 的类层次实现 GUI 特性(画图之类)。BBWindow 只是形式名,它可以替换,其意义就像将 MFC 换成 Qt 一样,这使得 IValBox 的类层次能够减小对特定 GUI 元素实现的依赖

UML: Old Hierarchy

C++ 类层次结构的设计方法学

设计要义:

使用 BBWindow 不是 IValBox 概念的基本部分。过分依赖 BBWindow,使得 BBWindow 难于替换

可变数据是实现的部分,当它侵入接口(抽象类)时,会影响接口的灵活性

Two-type interfaces: public interface vs. protected interface

interface: 有译接口,有译界面;有时代表函数,有时代表函数之聚集处(类、名字空间),凭上下文判断。按 [EFFECT CPP] Item 18 的说法:每一种接口都是客户与你的代码互动的手段

public interface: 给用户使用
protected interface: 给派生类使用

Strict Guide: Data members are better kept private so that writers of derived classes cannot mess with them.
推论: A protected interface should contain only functions, types, and constants.
更多 private data member 的讨论见 [EFFECT CPP] Item 22

Over strict?
Old Hierarchy 是不是 bad design?

实际上我用 MFC 时,大多数时候都这样做,这是大多数人用 GUI 框架的方法
问题不在绝对的 bad design 或 good design,而在于目标是什么?Application Development vs. Library Development, Cross-platform vs. Dedicated-platform

下面的改进设计比 Old Hierarchy 灵活而光鲜,但也带来的额外的负担(如理解和维护),Pros and Cons 自行抉择

分离实现和接口^

UML: Separate Implementation and Interface

C++ 类层次结构的设计方法学

接口线:接口继承形成的层次
实现线/扩展线:实现继承形成的层次

设计要义:

public 继承 vs. protected/private 继承

另一种表述是:接口继承 vs. 实现继承,见 [EFFECT CPP] Item 40。注意 Item 34 和这个设计无关,虽然标题相同,但那个是 for member function 的,这里是 for class 的

public 继承塑模 "is-a" 的关系(见 [EFFECT CPP] Item 32),而 protected/private 塑模 "implemented-in-terms-of" 的关系(见 [EFFECT CPP] Item 39)

protected 和 private 的区别:private 之实现止于直接派生类,而 protected 之实现可以进一步扩展

替代技术:public 继承 + Composition 复合

当用于实现域时,复合塑模 "implemented-in-terms-of" 的关系(和 protected/private 继承相同),见 [EFFECT CPP] Item 38

采用 protected/private 继承还是复合的判断,见 [EFFECT CPP] Item 39,如继承会造成 EBO (Empty Base Optimization) 空白基类最优化

替换实现^

这是分离实现和接口后得到的益处

UML: Substitute Implementation

C++ 类层次结构的设计方法学

图中的 BBSlider 表示 BBIValSlider 可藉由以存在的更特定的 GUI 元素实现,而不是更一般的 BBWindow,就像是从 MFC 的 CWnd 改为了 CSliderCtrl

使用同样的方法进行扩展就能得到 Big One:

UML: Substitute Implementation, Complicated

C++ 类层次结构的设计方法学

无需纠结上图具体含义,这里的设计推论更有意思:一个系统展现给用户的应该是一个抽象类的层次结构,其实现所用的是一个传统的层次结构
有点教条吧?试问,传统的层级结构从何而来?我们要做一个横跨多种 GUI 框架之上的框架么?

重复基类^

用 virtual 基类消除 replicated base class 重复基类,见 [EFFECT CPP] Item 40

这种用法的目的有二:

粘合 (glue) 两个不相干的类。这是我们应该忘掉的 virtual 多继承,连 Bjarne 也说它是 crude, effective, and important, but not very interesting. 为了下面的共享实现,这是有逻辑意义的 共享实现^

UML: Share Implementation

C++ 类层次结构的设计方法学

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/ppdps.html