"設(shè)計模式我學(xué)過呀,就是沒用過"
寫在前面
在開發(fā)中,不使用設(shè)計模式也不是不可以,但是用好設(shè)計模式能幫忙我們更好的去解決實際問題。
其實,我們天天都在和設(shè)計模式打交道,很多人卻完全不知道自己在使用設(shè)計模式,你有這種感覺嗎?
一個不好笑的笑話:
世界上有10種人,一種是懂設(shè)計模式的,一種是不懂設(shè)計模式的。
不會有人來問我,還有8種在哪里?大家覺得我該怎么回答。

什么是設(shè)計模式
設(shè)計模式( Design Pattern )代表了最佳的實踐,通常被有經(jīng)驗的面向?qū)ο蟮能浖_發(fā)人員所采用。設(shè)計模式是軟件開發(fā)人員在軟件開發(fā)過程中面臨的一般問題的解決方案。這些解決方案是眾多軟件開發(fā)人員經(jīng)過相當長一段時間的試驗和錯誤總結(jié)出來的。
前人種樹,后人乘涼
我們可以從以下三個關(guān)鍵點來理解設(shè)計模式:
最佳實踐 解決方案 試驗和錯誤總結(jié)
從上面的三個關(guān)鍵點中可以總結(jié)出,設(shè)計模式就是在針對編碼過程中遇到的問題總結(jié)出來的最佳解決方案。
那么這些問題指的是什么問題呢?
面向?qū)ο蟮某绦驊?yīng)該具有可維護性、代碼可復(fù)用性、擴展性及靈活性,要解決的問題就是代碼可維護性問題、復(fù)用性問題、擴展性問題及靈活性問題。
簡單來說,設(shè)計模式就是指導(dǎo)你如何寫出可維護、可復(fù)用、可擴展及靈活的代碼。
在1995年,由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 四人合著出版了一本名為 Design Patterns - Elements of Reusable Object-Oriented Software(中文譯名:設(shè)計模式 - 可復(fù)用的面向?qū)ο筌浖兀?的書,四位作者合稱 GOF(四人組,全拼 Gang of Four),該書收錄了23種設(shè)計模式,是軟件設(shè)計模式領(lǐng)域的里程碑。所有有時候設(shè)計模式我們稱之為GoF23。
設(shè)計模式的原則
開閉原則
開閉原則(Open-Closed Principle,簡稱OCP)是指一個軟件實體如類、模塊和函數(shù)應(yīng)該對擴展開放,對修改關(guān)閉。所謂的開閉,也正是對擴展和修改兩個行為的一個原則。
強調(diào)的是用抽象構(gòu)建框架,用實現(xiàn)擴展細節(jié)??梢蕴岣哕浖到y(tǒng)的可復(fù)用性及可維護性。開閉原則,是面向?qū)ο笤O(shè)計中最基礎(chǔ)的設(shè)計原則。它指導(dǎo)我們?nèi)绾谓⒎€(wěn)定靈活的系統(tǒng),例如:我們版本更新,我盡可能不修改源代碼,但是可以增加新功能。
依賴倒置原則
依賴倒置原則(Dependence Inversion Principle簡稱DIP)是指設(shè)計代碼結(jié)構(gòu)時,高層模塊不應(yīng)該依賴底層模塊,二者都應(yīng)該依賴其抽象。抽象不應(yīng)該依賴細節(jié);細節(jié)應(yīng)該依賴抽象。
通過依賴倒置,可以減少類與類之間的耦合性,提高系統(tǒng)的穩(wěn)定性,提高代碼的可讀性和可維護性,并能夠降低修改程序所造成的風(fēng)險。
單一職責(zé)原則
單一職責(zé)(Simple Responsibility Pinciple,簡稱SRP)是指不要存在多于一個導(dǎo)致類變更的原因。假設(shè)我們有一個 Class 負責(zé)兩個職責(zé),一旦發(fā)生需求變更,修改其中一個職責(zé)的
邏輯代碼,有可能會導(dǎo)致另一個職責(zé)的功能發(fā)生故障。這樣一來,這個 Class 存在兩個導(dǎo)致類變更的原因。如何解決這個問題呢?我們就要給兩個職責(zé)分別用兩個 Class 來實現(xiàn),進行解耦。
后期需求變更維護互不影響。這樣的設(shè)計,可以降低類的復(fù)雜度,提高類的可 讀 性 , 提 高 系 統(tǒng) 的 可 維 護 性 , 降 低 變 更 引 起 的 風(fēng) 險 。總 體 來 說 就 是 一個Class、Interface、Method 只負責(zé)一項職責(zé)。
接口隔離原則
接口隔離原則(Interface Segregation Principle,簡稱ISP)是指用多個專門的接口,而不使用單一的總接口,客戶端不應(yīng)該依賴它不需要的接口。這個原則指導(dǎo)我們在設(shè)計接口時
應(yīng)當注意以下幾點:
一個類對一類的依賴應(yīng)該建立在最小的接口之上。 建立單一接口,不要建立龐大臃腫的接口。 盡量細化接口,接口中的方法盡量少(不是越少越好,一定要適度)。
接口隔離原則符合我們常說的高內(nèi)聚低耦合的設(shè)計思想,從而使得類具有很好的可讀性、可擴展性和可維護性。我們在設(shè)計接口的時候,要多花時間去思考,要考慮業(yè)務(wù)模型,
迪米特法則
迪米特原則(Law of Demeter,簡稱LoD)是指一個對象應(yīng)該對其他對象保持最少的了解,又叫最少知道原則(Least Knowledge Principle,簡稱LKP),盡量降低類與類之間的耦合。
迪米特原則主要強調(diào)只和朋友交流,不和陌生人說話。出現(xiàn)在成員變量、方法的輸入、輸出參數(shù)中的類都可以稱之為成員朋友類,而出現(xiàn)在方法體內(nèi)部的類不屬于朋友類。
里氏替換原則
里氏替換原則(Liskov Substitution Principle,簡稱LSP),在面向?qū)ο蟮某绦蛟O(shè)計中,里氏替換原則是對子類的特別定義,這里給出兩個定義:
如果對每一個類型為S的對象o1,都有類型為T的對象o2,使得以T定義的所有程序P在所有的對象o1都代換成o2時,程序P的行為沒有發(fā)生變化,那么類型S是類型T的子類型。 程序中的對象應(yīng)該是可以在不改變程序正確性的前提下被它的子類所替換的。
以上兩種定義,反過來就不成立了,有子類出現(xiàn)的地方,父類未必就能適應(yīng)。
我們可以對里氏替換原則歸納為:
子類可以實現(xiàn)父類的抽象方法,但不能覆蓋父類的非抽象方法。
子類中可以增加自己特有的方法。
當子類的方法重載父類的方法時,方法的前置條件(即方法的輸入/入?yún)ⅲ┮雀割惙椒ǖ妮斎雲(yún)?shù)更寬松。
當子類的方法實現(xiàn)父類的方法時(重寫/重載或?qū)崿F(xiàn)抽象方法),方法的后置條件(即方法的輸出/返回值)要比父類更嚴格或相等。
使用里氏替換原則有以下優(yōu)點:
約束繼承泛濫,開閉原則的一種體現(xiàn)。 加強程序的健壯性,同時變更時也可以做到非常好的兼容性,提高程序的維護性、擴展性。降低需求變更時引入的風(fēng)險。
合成復(fù)用原則
合成復(fù)用原則(Composite/Aggregate Reuse Principle,簡稱CARP)是指盡量使用對象組合(has-a)/聚合(contanis-a),而不是繼承關(guān)系達到軟件復(fù)用的目的??梢允瓜到y(tǒng)更加靈活,降低類與類之間的耦合度,一個類的變化對其他類造成的影響相對較少。繼承我們叫做白箱復(fù)用,相當于把所有的實現(xiàn)細節(jié)暴露給子類。
組合/聚合也稱之為黑箱復(fù)用,對類以外的對象是無法獲取到實現(xiàn)細節(jié)的。要根據(jù)具體的業(yè)務(wù)場景來做代碼設(shè)計,其實也都需要遵循 OOP模型。
tips
學(xué)習(xí)設(shè)計原則,學(xué)習(xí)設(shè)計模式的基礎(chǔ)。在實際開發(fā)過程中,并不是一定要求所有代碼都遵循設(shè)計原則,我們要考慮人力、時間、成本、質(zhì)量,不是刻意追求完美,要在適當?shù)膱鼍白裱O(shè)計原則,體現(xiàn)的是一種平衡取舍,幫助我們設(shè)計出更加優(yōu)雅的代碼結(jié)構(gòu)。
另外:如果大家覺得還是沒有理解上面的幾個原則,那我下一篇文章使用代碼來詮釋。
設(shè)計模式的種類
設(shè)計模式分為三類:
創(chuàng)建型模式 行為性模式 結(jié)構(gòu)性模式
三種模式的分類如下:

經(jīng)典案例
我們最初剛剛開始接觸JDBC那會,第一個JDBC編程如下:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class JdbcDemo {
public static final String URL = "jdbc:mysql://localhost:3306/tian";
public static final String USER = "root";
public static final String PASSWORD = "123456";
public static void query() throws Exception {
Class.forName("com.mysql.jdbc.Driver");//1
Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);//2
Statement stmt = conn.createStatement();//3
ResultSet rs = stmt.executeQuery("SELECT id, name, age FROM m_user where id =1");//4
while(rs.next()){
System.out.println("name: "+rs.getString("name")+" 年齡:"+rs.getInt("age"));
}
}
}
這個案例中,我們可以把JDBC編程分為五個步驟。
一個查詢寫了五個步驟,再來個新增又寫五個步驟,再來個刪除又寫五個步驟....長此以往下去,真的成為“搬磚人了”,這是不使用任何設(shè)計模式的代價。
天天寫這種重復(fù)的代碼,自己很累,工作效率低,長此以往的下去,就算你干了10年還不如很多人一年的工作經(jīng)驗。
推薦書籍
1.《大話設(shè)計模式》
2.《Head First設(shè)計模式》
3.《設(shè)計模式之禪》
大家可以從三本書中,選擇自己最喜歡的,其實都講的挺好的,但我們只需選擇最適合適合自己的才是王道。
總結(jié)
設(shè)計模式的本質(zhì):設(shè)計模式用于承載復(fù)雜的業(yè)務(wù)邏輯,使寫出的代碼簡潔、易擴展 。
你可以不用學(xué)設(shè)計模式,照樣寫代碼很溜、照樣能實現(xiàn)功能、照樣能領(lǐng)到那點點薪資。有點志氣的、有點追求的、有點報復(fù)的人,肯定會學(xué)設(shè)計模式。
tips
本人從今天開始,開啟架構(gòu)師學(xué)習(xí)之旅,主要內(nèi)容如下:
設(shè)計模式 分布式與高并發(fā)(線程、JUC等) 分布式與微服務(wù)(Spring Boot、Spring Cloud、Dubbo) Spring源碼分析 Mybatis源碼分析 Dubbo源碼 性能優(yōu)化(JVM、Tomcat、MySQL) 工具(Maven、Git、Docker、K8S等)
— 【 THE END 】— 本公眾號全部博文已整理成一個目錄,請在公眾號里回復(fù)「m」獲取! 3T技術(shù)資源大放送!包括但不限于:Java、C/C++,Linux,Python,大數(shù)據(jù),人工智能等等。在公眾號內(nèi)回復(fù)「1024」,即可免費獲?。?!



