第1章 面向对象思想数据库
第2章 抽象编程
第3章 面向对象设计设计模式
第4章 类和方法数据结构
第8章 继承与替换模块化
第1章 面向对象思想
第2章 抽象
第3章 面向对象设计
第4章 类和方法
第5章 消息,实例和初始化
第6章 案例研究: 八皇后问题
第7章 研究研究: 台球游戏
第8章 继承与替换
第9章 案例研究: 纸牌游戏
第10章 子类和子类型
第11章 静态行为和动态行为
第12章 替换的本质
第13章 多重继承
第14章 多态及软件复用
第15章 重载
第16章 改写
第17章 多态变量
第18章 泛型
第19章 容器类
第20章 案例研究: 标准模板库
第21章 框架
第22章 框架实例: AWT和Swing
第23章 对象互连
一种考虑对象互连的方式就是研究可视性(visibility)和依赖性(dependency)这两个概念.可视性这个软件工程术语描述了关于名称的特性----经过该名称句柄能够存取对象.若是对象的名称是合法的且表明该对象,那么在这个特定的环境下,该对象就是可见的.一般,用于描述可视性的相关术语还包括标识符的范畴(scope)
可视性与连通性的关系体如今: 若是咱们可以控制并下降做为标识符的名称的可见性,那么就能更加容易肯定应该如何使用标识符.
依赖性这个概念将两个对象或者类联系起来.在不存在另一个对象的条件下,若是一个对象的存在无任何意义,咱们就说该对象依赖于另外那个对象.例如,子类几乎老是依赖于它的父类.
23.1 耦合和内聚
耦合(coupling)和内聚(cohesion)的思想提供了一个框架,用于评价对象和类的应用是否有效.耦合描述了类之间的关系,而聚合描述了类内部的关系.所以,若是想要下降类之间的互连性,能够经过减小类之间的耦合来实现.另外一方面,设计良好的类应该具备特定的目的;全部元素都应该与一个任务相关.这意味着在一个良好的设计中,类内部的元素应该具备内部的内聚性
23.1.1 耦合的种类
类之间的耦合能够有各类缘由,其中某些耦合比另一些耦合更可接受或更理想.从最差到较好的耦合以下面所示
内部数据耦合
全局数据耦合
控制(或顺序)耦合
组件耦合
参数耦合
子类耦合
内部数据耦合发生在当一个类的实例直接修改另一个类中的本地数据值(实例变量)时.
class SneakyModifier { public: void sneaky() { // change my friends name myFriend->name = "Lucy"; } Person * myFriend; }; class Person { public: Person() { name = "Larry"; } string name; };
内部数据耦合这种作法很是很差的缘由在于,这种方式使得想要独立理解类变得很是复杂.若是某个开发者只负责当前的类,那么若是这个类的内部数据字段戏剧性地被外部的某种行为所修改,该开发者将如何知道这一行为呢?这种作法将使程序很是难以理解和推断,应该尽量地避免.
全局数据耦合发生在两个或者更多个类都依赖于公用的全局数据结构而绑定到一块儿的时候
double todaysDow; class One { public: void setDow() { todaysDow = 9473; } }; class Two { public: void printDow() { cout << "Today the Dow hit " << todayDow; } };
一样,这种耦合形式很差的缘由在于独立理解类会变得很是复杂.每一个类自身都是不完整的,只有同时研究多个类定义时,才可以理解这些类之间的相互做用.可是,全局数据耦合有时是不可避免的
在实践中,如何区分下面这两种全局变量很是重要.在涉及多文件的程序中,某些全局变量具备文件范畴(file scope),这意味着只能在一个文件中使用这些变量.另外一种全局变量则具备程序范畴(program scope),这意味着能够在程序中的任何位置对其进行修改.了解具备程序范畴的全局变量的使用比了解具备文件范畴的全局变量的使用要困可贵多
许多语言都提供了用来在单独类与整个程序之间控制名称可视性的技术.这方面的实例包括C++语言中的名称空间,Java语言中的包以及Object Pascal语言中的单元等.这些特征支持某些名称具备超过一个单独类但却小于整个程序的范畴.当对象之间经过这种数值进行交互时,程序之间发生做用的部分减小了,所以这种作法将比对象之间经过真正的全局变量进行交互的作法要更好,可是,这种耦合仍然难以理解,而且也应该尽量地避免
在面向对象框架中,可能存在的代替全局数据耦合的方法就是创建新类,整个类负责"管理"数据值,全部对全局数值的存取都需通过这个类(这种方法相似于咱们使用存取函数来屏蔽在对象内部直接存取本地数据的作法).这种技术将全局数据耦合下降到参数耦合级别上,而参数耦合更容易理解和控制.在Java语言中,不存在全局变量,全部的数值都必须经过类来管理
class MyClass { public: void mustDoFirst() { ... } void doSecond() { ... } void doThird() { ... } };
控制或者顺序耦合发生在一个类必须以一种由任意位置控制的特定的顺序来执行操做时.数据库系统可能会顺序经历如下几个步骤:执行初始化阶段,读取当前记录,更新记录,删除记录,以及产生报告等.可是,每一个阶段都经过不一样的例程来调用,而且调用顺序依赖于不一样位置上的代码.控制耦合的存在说明类的设计者只需跟随低级别的抽象便可(每一个步骤都对应一条指令,“处理数据库”).即便控制耦合不可避免,一般也会谨慎地要求正被顺序化的类必须确保其自身可以以正确的顺序实现操做,而并不依赖于调用者的正确处理
组件耦合发生在一个类包含的数据字段或数值为另一个类的实例时.组件耦合的这种关系是一种理想的耦合方式.容器显然知道它所包含的数值所属的类,可是它所包含的元素却不该该知道关于它所处的容器的状况
class Set { . . . private: List data; };
参数耦合发生在一个类必须调用另一个类的服务和例程时,此时两个类之间所发生的惟一关系就是一个类须要为另外一个类提供参数数目,类型和返回值类型.这种耦合形式很常见,容易理解,并易于验证(例如,使用检查参数调用与定义不匹配的工具);所以,这是一种最良好的耦合方式
class MyClass { public: void doSomething(Set aSet) { // do something using the argument value . . . } }
子类耦合是面向对象编程所特有的.它描述了一个类与其父类之间的关系.经过继承,子类的实例能够被当作父类的实例
class Parent { . . . } class Child extends Parent { . . . }
23.1.2 内聚的种类
类的内部内聚性是该结构之中各个元素之间绑定程度的量度.与耦合相似,从最弱的内聚(最少指望的)到最强的内聚(最指望的)依次排列的结果以下所示
随机内聚
逻辑内聚
时间内聚
通讯内聚
顺序内聚
功能内聚
数据内聚
随机内聚发生在没有明显缘由而对一个类的元素进行分组时.一般这都是对一个大型程序随意划分红多个部分(相似于模块化)的结果.这每每是设计很差的一个标志.在面向对象框架中,当类由多个无关的方法组成时,咱们就称这种状况为随机内聚
逻辑内聚发生在每一个数据或控件中,类的各个元素之间存在着逻辑的联系但并不存在实际的联系时.若是算术函数库(正弦, 余弦等函数)中的各个函数都在不参照其余函数的条件下独立实现各自的功能,那么该函数库就展现了一种逻辑内聚
时间内聚发生在因为多个元素几乎同时使用而绑定到一块儿时.典型的例子就是用来实现程序初始化的类.这里,更好的设计是经过不一样的类来实现不一样的初始化活动,使每一个类都负责更具体的后续行为
通讯内聚发生在一个类的全部方法因为须要存取相同的"输入/输出"数据或设备而组合到一块儿时.类将扮演数据或者设备的"管理者"的角色
23.1.3 德墨特尔法则
23.1.4 类级别可视性与对象级别可视性
23.1.5 活动值
23.2 子类客户和用户客户
23.3 存储控制和可视性
23.3.1 Smalltalk语言中的可视性
23.3.2 C++语言中的可视性
23.3.3 Object Pascal语言中的可视性
23.3.4 Java语言中的可视性
23.3.5 Objective-C语言中的可视性
第24章 设计模式
第25章 反射和内省
第26章 分布式对象
第27章 实现
参考文献