一、模板模式 1、模板模式(Template Method pattern):指定義一個演算法的骨架,並允許子類為一個或者多個步驟提供實現。模板方法使得子類可以在不改變演算法結構的情況下,重新定義演算法的某些步驟。(屬於行為型模式) 2、適用場景 一次性實現一個演算法的不變的部分,並將可變的行為留給子類來實 ...
一、模板模式
1、模板模式(Template Method pattern):指定義一個演算法的骨架,並允許子類為一個或者多個步驟提供實現。模板方法使得子類可以在不改變演算法結構的情況下,重新定義演算法的某些步驟。(屬於行為型模式)
2、適用場景
- 一次性實現一個演算法的不變的部分,並將可變的行為留給子類來實現
- 各子類中公共的行為被提取出來並集中到一個公共的父類中,從而避免代碼重覆
3、優點
- 提高代碼的復用性
- 提高代碼的擴展性
- 符合開閉原則
4、缺點
- 類數目的增加
- 間接地增加了系統實現的複雜度
- 繼承關係自身缺點,如果父類添加新的抽象方法,所有子類都要改一遍
5、應用場景舉例
比如辦理入職流程:填寫入職登記表-->列印簡歷-->複印學歷-->複印身份證-->簽訂勞動合同-->辦理工牌-->安排工位。
比如平時炒菜流程:洗鍋-->點火--> 熱鍋-->上油-->下菜-->翻炒-->放調料-->出鍋。
再如趙本山問宋丹丹:“如何把大象放進冰箱?”宋丹丹答:“第一步:打開冰箱門,第二步:把大象塞進冰箱,第三步:關閉冰箱門”。趙本山再問:“怎麼把長頸鹿放進冰箱?”宋丹丹答:“第一步:打開冰箱門,第二步:把大象拿出來,第三步:把長頸鹿塞進去,第四步:關閉冰箱門”,這些都是模板模式的體現。
例子1:以簡單的網校課程創建流程為例:發佈預習資料-->線上直播-->提交筆記-->佈置作業-->檢查作業。
首先定義一個NetworkCourse網課抽象類:
上面代碼中有個鉤子方法,主要是用來干預執行流程,使得我們控制行為流程更加靈活、更符合實際業務的需求。鉤子方法的返回值一般為適合條件分支語句的返回值(如boolean、int等),可根據真實業務場景來決定是否需要用鉤子方法。
接下來定義一個JavaCourse課程類:
定義一個BigDataCourse課程類:
客戶端測試代碼:
運行結果:
例子2:利用模板模式重構JDBC操作業務場景。
定義一個JdbcTemplate模板類,封裝所有的JDBC操作。以查詢為例,每次查詢的表不同,返回的數據結構也不一樣。我們針對不同的數據,都要封裝成不同的實體對象。而每個實體封裝的邏輯都是不一樣的,但封裝前和封裝後的處理流程是不變的,因此可以用模板模式來設計這樣的業務場景。 先定義一個約束ORM邏輯的介面RowMapper:
再定義一個封裝了所有處理流程的抽象類JdbcTemplate:
定義一個實體類User:
定義一個資料庫操作類UserDao:
客戶端測試代碼:
6、模板模式在源碼中的應用
① 先看JDK中的AbstractList:
我們看到get()是一個抽象方法,那麼它的邏輯就是交給子類來實現,ArrayList就是AbstractList的子類。同理,有AbstractList就有AbstractSet和AbstractMap,有興趣可自行研究。還有一個每天都在用的HttpServlet,有service()、doGet()和doPost()方法,都是模板方法的抽象實現。
② Mybatis框架中的BaseExecutor類,是一個基礎的SQL執行類,實現了大部分的SQL執行邏輯,然後把幾個方法交給子類定製化完成,源碼如下:
如doUpdate()、doQuery()等方法都交由子類來實現,如下類圖:
二、適配器模式
1、適配器模式(Adapter Pattern):指將一個類的介面轉換成客戶期望的另一個介面,使原本介面不相容的類可以一起工作。(屬於結構型設計模式)
2、適用場景
- 已經存在的類,它的方法和需求不匹配(方法結果相同或相似)的情況
- 適配器模式不是軟體設計階段考慮的設計模式,是隨著軟體維護,由於不同產品、不同廠家造成功能類似而介面不相同情況下的解決方案(有點亡羊補牢的感覺)
3、優點
- 能提高類的透明性和復用,現有的類復用但不需要改變
- 目標類和適配器類解耦,提高程式的擴展性
- 在很多業務場景中符合開閉原則
4、缺點
- 適配器編寫過程需要全面考慮,可能會增加系統的複雜性
- 增加代碼閱讀難度,降低代碼可讀性,過多使用適配器會使系統代碼變得凌亂
5、應用場景舉例
比如電源插轉換頭、手機充電轉換頭、顯示器轉接頭。
例子1:在中國民用電都是220V交流電,但我們手機使用的鋰電池使用5V直流電。因此,我們給手機充電時就需要使用電源適配器來進行轉換。下麵代碼還原場景:
定義一個AC220類,表示220V交流電:
定義一個DC5介面,表示5V直流電的標準:
定義一個電源適配器PowerAdapter類:
客戶端測試代碼:
上面的案例中,通過增加PowerAdapter電源適配器,實現了二者的相容。
例子2:重構第三方登錄自由適配的業務場景。
以前開發的老系統應該都有登錄介面, 但隨著業務的發展和社會的進步,單純地依賴用戶名密碼登錄顯示不能滿足用戶需求了。現在,我們大部分系統都已經支持多種登錄方式,如QQ登錄、微信登錄、手機登錄等,同時保留用戶名密碼的登錄方式。雖然登錄形式豐富了,但登錄後的處理邏輯可不必改變,同樣是將登錄狀態保存到session,遵循開閉原則。
首先定義統一的返回結果Result類:
假設老系統的登錄邏輯SignInService:
為了遵循開閉原則,老系統的代碼我們不去修改。下麵開始重構,先定義User類:
定義一個第三方登錄新類SignInForThirdService繼承原來的邏輯,運行非常穩定的代碼我們不去改動:
客戶端測試代碼:
通過這麼一個簡單的適配,完成了代碼相容。當然,代碼還可以更加優雅,根據不同的登錄方式,創建不同的Adapter。
首先,定義一個LoginAdapter介面:
分別實現不同的登錄適配,QQ登錄LoginForQQAdapter類:
微信登錄LoginForWechatAdapter類:
然後定義第三方登錄相容介面IPassportForThird:
實現相容PassportForThirdAdapter類:
客戶端測試代碼:
類結構圖:
至此,我們在遵循開閉原則的前提下,完整地實現了一個相容多平臺登錄的業務場景。適配器模式主要解決的是功能相容問題,且適配器的實現邏輯並不依賴於介面,我們完全可以將LoginAdapter介面去掉,加上介面只是為了代碼規範。上面的代碼可以說是策略模式、簡單工廠模式和適配器模式的綜合運用。
6、適配器模式在源碼中的應用
簡單看看適配器模式在源碼中的應用,SpringMVC的HandlerAdapter類,它也有多個子類: