第七章 什么是设计模式
1. 源代码是软件系统的主要设计文档
- 我们不应该认为软件设计就是一组和代码分离的UML图,UML图只是描述了设计的一部分。
- 软件项目的设计是一个抽像的概念。它和程序的概括形状、结构以及每一个模块、类和方法的详细形状和结构有关。
- 设计的最终体现在 源代码 中。
2.设计中臭味——腐化软件的气味
- 僵化性: 耦合性高,模块组件件关系太紧密,依赖性高,一动全动。
- 脆弱性: 改动一处,其他相关联的地方也会变动,引发意想不到的问题。
- 牢固性: 设计难以重用。
- 粘滞性: 这一点有点难以理解。
- 不必要的复杂性: 导入不必要的模块,组件或包。
- 不必要的重复: 随意copy,将可以的抽象隐藏起来,而且如果随处copy的代码(如果有错误)需要变动,得到处进行修改。
- 【案例】:开发中,打印空指针异常信息处理方法的例子
- 晦涩性: 模块难以理解。
-
设计中的臭味
3.保持尽可能好的设计
- 需求是项目中最不稳定的要素。
- 敏捷团队依靠变化来获取活力。
- 团队几乎不进行预先设计,因此不需要一个成熟的初始设计。
- 敏捷开发人员致力于保持设计尽可能的适当、干净、简单,并且使用许多的单元测试和验收测试支援。
- 敏捷软件开发知道要做的事情:
- 他们遵循敏捷实践去发现问题
- 他们应用设计原则去诊断问题
- 并且,他们应用适当的设计模式去解决问题
4.结论-什么是敏捷设计
-
敏捷设计是一个过程,不是一个事件。它是一个持续的应用原则、模式以及实践来改进软件的结构和可读性的过程。它致力于保持系统设计在任何时间都尽可能的简单、干净以及富有表现力。
5.臭味
- 设计中的臭味是一种症状,是可以主观进行度量的。这些臭味通常是由违反了这些原则中的一个或者多个导致的。
- 比如违反了开闭原则,会导致僵化性。
- 应用原则的目的是去除僵化性,当没有臭味时就不应该应用这些原则
6.敏捷设计之原则
- 单一职责原则(The Single Responsibility Principle,简称SRP)
- 开放——封闭原则(The Open-Close Principle,简称OCP)
- Liskov替换原则(The Liskov Substitution Principle,简称LSP)
- 接口隔离原则(The Interface Segregation Interface,简称ISP)
- 依赖倒置原则(The Dependency Inversion Principle,简称DIP)
第八章 单一职责原则(SRP)
- 内聚性:
-
一个模块的组成元素之间的功能相关性。把内聚性和引起一个模块或者类改变的作用力联系起来。
- 职责: 变化的原因。
- 原则的定义:就一个类而言,应该仅用一个引起它变化的原因。
- 描述:
- 每一个职责都是变化的一条轴线。当需求变化时,该变化反应为类的职责的变化。如果一个类承担了多于一个的职责,那么引起它变化的原因就会有多个。
- 如果一个类承担的职责过多,就等于把这些职责耦合在一起。一个职责的变化可能会削弱或者抑制这个类完成其他职责的能力。
- 这种耦合导致脆弱的设计,当变化发生时,设计会遭受意想不到的破坏。
- Employee的例子
- Employee类包含了业务规则和对于持久化的控制。
- 业务规则往往会频繁的变化,而持久化的方式却不会如此频繁的变化。
- 测试驱动开发的实践常常会远在设计出现臭味之前就迫使我们分离这两个职责。
- 一个实例:
- SpringIOC源码中BeanFactory的设计。
- getBaen()和getBeanDefinition()、registerBeanDefinition()的分离。
第九章 开放-封闭原则(OCP)
- 原则的定义:
-
软件实体(类,模块、函数等等)应该是可以扩展的,但是不可修改的。
- 描述:
- 对于扩展是开放的
- 对于更改的封闭的
-
开闭的原则描述
- 本质: 构造抽象来隔离引起的变化
- 如何知道变化的发生:
- 进行适当的调查,提出正确的问题,并且使用我们的经验和一般常识,最终,直到我们会一直等到变化发生的时候才采取行动。
- 结论:
-
在许多方面,OCP都是面向对象设计的核心所在,遵循这个原则可以带来巨大好处。比如,灵活性,可重用性以及可维护性。
第十章 Liskov替换原则(LSP)
- 定义:
-
子类型必须能够替换掉它们的基类型
- 背后的本质:继承
- 描述: 若对每个类型S的对象o1,都存在一个类型T的对象o2,使得在所有针对T编写的程序P中,用o1替换o2后,程序P行为功能不变,则S是T的子类型。
- 隐藏的问题:一般违反LSP原则的同时,也潜在的违反了OCP原则。
- Rectangle类与Square类违反了LSP的有趣例子
- 结论:
-
一个模型,如果孤立地看,并不具有真正意义上的有效性。在考虑一个特定设计是否恰当时,不能完全孤立地来看这个解决方案。必须要根据该设计的使用者所做出的合理假设来审视它。
- 基于契约式设计(约定大于配置)
- 契约:是通过为每个方法声明的前置条件和后置条件来指定的。
- 要使一个方法得以执行,前置条件必须为真。执行完毕后,该方法要保证后置条件为真。
-
继承的适用性
第十一章 接口隔离原则
- **定义:**不应该强迫客户依赖它们不用的方法
- 胖类:意味着高耦合性,当一个客户程序要求该胖类进行一个改动时,会影响到所有其他的客户程序。
- 分离客户就是分离接口
-
接口隔离原则描述
- 分离接口的两种方式:
- 使用委托分离接口
- 使用多重继承分离接口
第十二章 依赖倒置原则(DIP)
-
定义:
-
a.高层模块不应该依赖于低层模块。两者都应该依赖于抽象。
b.抽象不应该依赖于细节。细节应该依赖于抽象。 -
依赖倒置原则描述
-
设计的层次化;
- 所有结构良好的面向对象架构都具有清晰的层次定义,每个层次通过一个定义良好的、受控的接口向外提供了一组内聚的服务。
- 这里的倒置不仅仅是依赖关系的倒置,它也是接口所有权的倒置。
-
依赖于抽象: 程序中所有的依赖关系都应该终止于抽象类或者接口。
- 任何变量都不应该持有一个指向具体类的指针或者引用。
- 任何类都不应该从具体类派生。
- 任何方法都不应该覆写它的任何基类中的已经实现了的方法。
-
java是静态编程语言,python是动态编程语言。