软件设计原则
软件设计主要关注如何设计一个高质量软件系统,使其满足用户需求,同时具有良好的可维护性、可扩展性、可重用性、可移植性等好的特性。其主要分为软件架构设计和详细设计两个阶段。本课程的主要关注面向对象(
面向对象过程主要分为几个阶段:面向对象分析并结合领域模型确立软件架构、面向对象设计和面向对象编程,即从高层设计向低层设计演进。

面向对象分析(OOA)、面向对象设计(OOD)和面向对象编程(OOP)
一般来说,后两者,即从面向对象设计到面向对象编程这一部分,相对较为简单,只是将设计的类和对象映射到编程语言中。而前两者之间的跨越则是一个较为复杂的过程,需要利用丰富的经验和熟练度来完成。这就需要长期的实践和积累。

从分析到设计的过程几乎等同于“魔法”
为了有助于软件设计的工程化,在长期的实践和积累中,人们总结出了一些软件设计原则。利用这些原则,可以帮助我们更好的设计软件系统,提高软件系统的质量。
面向对象设计原则概述
知名软件大师
基于这一出发点,人们总结出了一些面向对象设计原则。这些原则并不是孤立存在的,他们相互依赖,互相补充。
单一职责原则
定义 一个对象应该只包含单一的职责,并且该职责被完整地封装到一个类中。
另一种定义 就一个类而言,应该仅有一个引起它变化的原因。
变化的原因
一个类中的变化指由于需求点的变化而引起的变化。如果一个类有多个引起它变化的原因,那么这个类就有多个职责。
一般来说,一个类承担的职责越多,那么它被复用的可能性越小。当职责过多时,其中的一个职责发生变化,可能会影响其他职责,导致系统的不稳定。另外,遵循单一职责原则也是实现高内聚、低耦合的指导方针。
职责
类的职责指类在面向对象编程中承担的功能和任务。一般来说,类的职责分为两种:
- 数据职责:负责存储数据,如类的属性。
- 行为职责:负责完成某种功能,如类的方法。

利用单一职责原则优化设计
开闭原则
定义 一个软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。
开闭原则表示,在设计一个软件实体时,应该使其通过扩展来改变行为,而不是通过修改已有的代码来实现变化。开闭原则是抽象化的体现。

利用开闭原则优化设计
里氏替换原则
定义 如果对每一个类型为
另一种定义 所有引用基类(父类)的地方必能透明地使用其派生类(子类)的对象。
里氏替换原则(

利用 LSP 优化设计
依赖倒置原则
定义 高层模块不应该依赖于底层模块,二者都应该依赖于抽象;抽象不应该依赖于细节,细节应该依赖于抽象。
另一种定义 应当面向接口编程,而不是面向实现编程。
依赖倒转主要意为:代码要依赖抽象的类,而非具体的类。要针对接口或抽象类编程,而不是针对具体类编程。依赖倒转原则是实现开闭原则的重要手段。

利用依赖倒置原则优化设计
接口隔离原则
定义 客户端不应该依赖它不需要的接口。一旦一个接口过大,则需要将它分割成更细小的接口,使用该接口的客户端仅需知道与之相关的方法即可。
接口的说明
这里的接口不仅仅指 Java
中的 interface
。主要指类对外提供的方法,即与外部交互的方法。
接口隔离原则是讲,应当使用多个专门的接口,而非单一的总接口。此外,接口只应将客户端需要的方法暴露出来,而隐藏不需要的具体实现。接口隔离原则其实是对单一职责原则的扩展,是单一指责原则在接口层面的体现。

利用接口隔离原则优化设计
合成复用原则
定义 尽量使用对象组合,而不是继承来达到复用的目的。
合成复用原则是指,在新的对象里通过关联关系(包括组合关系和聚合关系)来使用一些已有的对象,使之成为新对象的一部分;新对象通过委派调用已有对象的方法达到复用已有对象的目的。这一可以减少继承带来的复杂性。继承是一种强耦合的关系,继承复用一般是静态的,不可在运行时发生改变,没有足够的的灵活性。而组合/聚合是一种弱耦合的关系,可以在运行时选择性地调用成员对象的操作,动态地改变对象的行为。

利用合成复用原则优化设计
迪米特法则
定义 每一个软件单位(类、模块、函数等)对其他的单位都只有最少的知识,而且局限于那些与本单位密切相关的软件单位。换句话说就是只与你的直接朋友通信。
迪米特法则的表述相对而言较为笼统,但它的核心思想就是降低软件单位(实体)之间通信的宽度和深度。这样,当一个单位发生修改时,就会尽可能地减少对其他单位的影响。
还有一种狭义的迪米特法则:如果两个类之间不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果其中一个类需要调用另一个类的方法,可以通过第三者转发这个调用。此外,经常变化的类应当被封装起来,其他类应该调用封装好的类来进行通信。狭义的迪米特法则关注类之间的耦合,而广义的迪米特法则关注对信息隐藏的控制。

利用迪米特法则优化设计
指导性建议
迪米特法则提供了以下指导性建议:
- 在类的划分上,应当尽量创建松耦合的类,类之间的耦合度越低,就越有利于复用,一个处在松耦合中的类一旦被修改,不会对关联的类造成太大波及;
- 在类的结构设计上,每一个类都应当尽量降低其成员变量和成员函数的访问权限;
- 在类的设计上,只要有可能,一个类型应当设计成不变类;
- 在对其他类的引用上,一个对象对其他对象的引用应当降到最低。