第6章 可以工作的类
//针对如何创建高质量的类,提供一些精辟的建议。
类的基础
1.类的基础:抽象数据类型
要理解面向对象编程,首先要理解ADT。
2.使用ADT的益处
可以隐藏实现细节;
改动不会影响到整个程序;
让接口能提供更多信息;
更容易提高性能;
让程序的正确性更显而易见;
程序更具自我说明性;
无需在程序内到处传递数据;
3.使用ADTs的指导建议:
把常见的底层数据创建为ADT并使用这些ADT,而不再使用底层数据
把文件这样的常用对象当成ADT
简单的事物也可当作ADT
不要让ADT依赖于其存储介质
良好的类接口
//创建高质量的类,第一步,可能也是最重要的一步,就是创建一个好的接口。
3.创建类的抽象接口的一些建议:
类的接口应该展现一致的抽象层次
一定要理解类所实现的抽象是什么
提供成对的服务
把不相关的信息转移到其它类中
尽可能让接口可编程,而不是表达语义
谨防在修改是破坏接口的抽象
不要添加与接口抽象不一致的公用成员
同时考虑抽象性和内聚性
4.良好的封装:
尽可能限制类和成员的可访问性
不要公开暴露成员数据
避免把私用的实现细节放入类的接口中
不要对类的使用者做出任何假设
避免使用友元类
不要因为一个子程序里仅使用公用子程序,就把它归入公开接口
让阅读代码比编写代码更方便
要格外警惕从语义上破坏封装性
留意过于紧密的耦合关系
“关注类的接口所表现出来的抽象,比关注类的内聚性更有助于深入的理解类的设计。”
有关设计和实现的问题
5.包含(has a “有一个 ”的关系):
包含是一个非常简单的概念,它表示一个类含有一个基本数据元素或对象。包含是面向对象编程的主力技术。
通过包含实现“有一个(has a)”的关系
在万不得已时通过private继承来实现“有一个”关系
警惕有超过7个数据成员的类
6.继承(is a “是一个 ”的关系):
用public继承实现“是一个(is a……)”的关系
要么使用继承并进行详细的说明,要么就不要用它
遵循Liskov替换原则(派生类必须能通过基类的接口而被使用,且使用者无需了解两者之间的差异)
确保只继承需要继承的部分
不要“覆盖”一个不可覆盖的成员函数(即:派生类中的成员函数不要与基类中不可覆盖的成员函数重名)
把共用的接口、数据和操作放到继承树中尽可能高的位置
只有一个实例的类是值得怀疑的
只有一个派生类的基类也是值得怀疑的
派生后覆盖了某个子程序。但在其中没做任何操作,这种情况也值得怀疑
避免让继承体系过深
尽量使用多态,避免大量的类型检查
让所有数据都是private(而非protected)
7.
要么使用继承并进行详细的说明,要么就不使用它。使用继承程序增加复杂度,是一种危险的技术,要尽量少用。
总结
- 类的接口应提供一致的抽象。很多问题都是由于违背该原则而引起的。
- 类的接口应该隐藏一些信息——如某个系统接口、某项设计决策、或者一些实现细节。
- 包含往往比继承更为可取——除非你要对“是一个/is a”的关系建模。
- 继承是一种有用的工具,但它却会增加复杂度。
- 类是管理复杂度的首选工具。