[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. **重寫**:已有的代碼非常復雜混亂,難以修改,重構的時間還不如重新寫一個來得快;根據需求另立一個項目,完全重寫。
## 為什么重構
* 重復的代碼太多,沒有復用性;難于維護,需要修改時處處都得改。
* 代碼的結構混亂,注釋也不清晰;沒有人能清楚地理解這段代碼的含義。
* 程序沒有拓展性,遇到新的變化,不能靈活的處理。
* 對象結構強耦合,業務邏輯太復雜,牽一發而動全身,維護時排查問題非常困難。
* 部分模塊性能低,隨著用戶的增長,已無法滿足響應速度的要求。
## 重構的時機
* 添加功能時
* 修補錯誤時
* 復審代碼時
## 如何重構
* 重命名
* 函數重構
* 提煉函數
* 去除不必要的參數
* 用對象取代參數
* 隱藏函數
## 最后的最后
* 編程不是工作的全部, 工作也不是生活的全部.
* 程序員拼到最后, 拼的是身體和見識
* 對于編程, 學習最重要; 對于學習, 理解最重要; 對于理解, 見識最重要