[toc]
## 设计模式玄吗
> 对于 10w 行以下的代码量的汉子来说,设计模式 = 玄学。
> 对于 10w ~ 50w 行代码量的汉子来说,设计模式 = 科学。
> 对于 50w 行以上代码量的汉子来说,设计模式 = 文学。
## 编程思想的三重境界
**宋代禅宗大师青原行思提出参禅的三重境界**:
> 参禅之初,看山是山,看水是水;
> 禅有悟时,看山不是山,看水不是水;
> 禅中彻悟,看山仍是山,看水仍是水。
1. **一重境界**:依葫芦画瓢。这属于初学阶段,以为设计模式只有书中提到的那几种模式,模式名称也能倒背如流。但真正要用时,还得去翻书,依关类图照般照改。
1. **二重境界**:灵活运用。这属于中级阶段,对每一种设计模式都非常熟悉,有较深入的思考,而且能够根据实际的业务场景选择合适的模式,并对相应的模式进行恰当的修改以符合实际需求。
1. **三重境界**:心中无模式。这算终于阶段,这里说无模式并非他不用设计模式,而是设计模式的理念已经融入他的灵魂和血液,他已经不在乎哪种具体的通用模式了,每一处代码都遵循了设计的原则,能灵活地创造和使用新的模式(可能这种模式他自己也不知道该叫什么名)。`这就是所谓的心中无模式却处处是模式`。
## SOLID 原则
* S——单一职责原则
* O——开放封闭原则
* L——里氏替换原则
* I——接口隔离原则
* D——依赖倒置原则
### 单一职责原则
* 一个类应该有且仅有一个原因引起它的变更。
* 一个类只负责一项功能或一类相似的功能
### 开放封闭原则
* 软件实体(如类、模块、函数等)应该对拓展开放,对修改关闭。
* 在增加一个功能时,应当尽可能地不去改动已有的代码;当修改一个模块时不应该影响到其他的模块。
### 里氏替换原则
* 所有能引用基类的地方必须能透明地使用其子类的对象。
* 只要父类能出现的地方子类就能出现(就可以用子类来替换他),反之,子类能出现的地方父类就不一定能出现(子类拥有父类的所有属性和行为,但子类拓展了更多的功能)。
### 接口隔离原则
* 客户端不应该依赖它不需要的接口。
* 用多个细粒度的接口来替代由多个方法组成的复杂接口,每一个接口服务于一个子模块。
* 建立单一接口,不要建立庞大臃肿的接口,尽量细化接口,接口中的方法尽量少。
* 要为各个类建立专用的接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用。
* 接口尽量小,但是要有限度 。当发现一个接口过于臃肿时,就要对这个接口进行适当的拆分
* 但是如果过小,则会造成接口数量过多,使设计复杂化;所以一定要适度。
### 依赖倒置原则
* 高层模块不应该依赖底层模块,二者都该依赖其抽象,抽象不应该依赖细节,细节应该依赖抽象。
* 把具有相同特征或相似功能的类,抽象成接口或抽象类,让具体的实现类继承这个抽象类(或实现对应的接口)。
* 抽象类(接口)负责定义统一的方法,实现类负责实现具体功能的实现。
## LoD 原则(Law of Demeter)
> 每一个逻辑单元应该对其他逻辑单元有最少的了解:也就是说只亲近当前的对象。
> 只和直接(亲近)的朋友说话,不和陌生人说话。
## KISS 原则(Keep It Simple and Stupid)
> 保持简单和愚蠢
> 简单就是说要让你的程序能简单、快速地被实现;
> 愚蠢是说你的设计要简单到傻瓜都能理解,即简单就是美!
## DRY 原则(Don’t Repeat Yourself)
> 不要重复自己
> 不要重复你的代码,即多次遇到同样的问题,应该抽象出一个共同的解决方法,不要重复开发同样的功能,也就要尽可能地提高代码的复用率。
## YAGNI 原则(You Aren't Gonna Need It)
> 你没必要那么着急,不要给你的类实现过多的功能,直到你需要他的时候再去实现。
> 只考虑和设计必须的功能,避免过度设计。只实现目前需要的功能,在以后需要更多功能时,可以再进行添加。
> 如无必要,勿增添复杂性。
> 软件开发是一场沟通博弈。
> 它背后的指导思想,就是尽可能快、尽可能简单地让软件运行起来
## Rule Of Three 原则
> 称为“三次法则”,指的是当某个功能第三次出现时,才进行抽象化,即事不过三,三则重构。
> 第一次去实现一个功能尽管大胆去做;
> 第二次做类似的功能设计时会产生反感,但是还是会去做;
> 第三次还要实现类似的功能做同样的事情时,就应该去审视是否有须要做这些重复劳动了,这个时候就应该去重构你的代码了
> 把重复或相似功能的代码进行抽象,封装成一个通过的模块或接口。
## CQS 原则(Command-Query Separation)
> 查询:当一个方法返回一个值来回应一个问题的时候,它就具有查询的性质;
> 命令:当一个方法要改变对象的状态的时候,它就具有命令的性质;
> 保证方法的行为严格的是命令或者是查询,这样查询方法不会改变对象的状态,没有副作用;而会改变对象的状态的方法不可能有返回值
> 一个接口中,尽量不要有查数据又有更新(修改或插入)数据的操作。
## 什么是重构
1. **名词**:对软件内部结构的一种调整,目的是在不改变软件可观察行为的前提下,提高其可理解性,降低其修改成本。
1. **动词**:使用一系列重构手法,在不改变软件可观察行为的前提下,调整软件的结构
## 重构和重写的区别
1. **重构**:不是对已有代码的全盘否定,而是对不合理的结构进行调整,合理的模块进行改动;利用更好的方式,写出更好,更有维护性代码。
1. **重写**:已有的代码非常复杂混乱,难以修改,重构的时间还不如重新写一个来得快;根据需求另立一个项目,完全重写。
## 为什么重构
* 重复的代码太多,没有复用性;难于维护,需要修改时处处都得改。
* 代码的结构混乱,注释也不清晰;没有人能清楚地理解这段代码的含义。
* 程序没有拓展性,遇到新的变化,不能灵活的处理。
* 对象结构强耦合,业务逻辑太复杂,牵一发而动全身,维护时排查问题非常困难。
* 部分模块性能低,随着用户的增长,已无法满足响应速度的要求。
## 重构的时机
* 添加功能时
* 修补错误时
* 复审代码时
## 如何重构
* 重命名
* 函数重构
* 提炼函数
* 去除不必要的参数
* 用对象取代参数
* 隐藏函数
## 最后的最后
* 编程不是工作的全部, 工作也不是生活的全部.
* 程序员拼到最后, 拼的是身体和见识
* 对于编程, 学习最重要; 对于学习, 理解最重要; 对于理解, 见识最重要