簡述
這種模式是很比較簡單的一種模式,相信大家工作過程中直接或間接用到過很多。 下面我們看下對應的UML圖和相應的程式碼
圖例
程式碼
現在我們臆想一個業務場景,比如對接不同的支付渠道(大部分都是基於官方提供的sdk整合),假設我們步驟如下:
1. 簽名鑑權
2. 統一下單
3. 返回支付資訊
複製程式碼
對接支付寶支付的程式碼:
package design.pattern;
public class AliPay {
/**
* start
*/
public void start() {
System.out.println("某種操作,我現在只是一個範例");
}
/**
* 介面鑑權
*/
public void auth() {
System.out.println("支付寶--生成sign校驗是否合法");
}
/**
* 向第三方下訂單
*/
public void thirdOrder() {
System.out.println("支付寶--下訂單介面");
}
/**
* 獲取支付平臺資訊
*/
public void getPayInfo() {
System.out.println("支付寶--獲取支付平臺資訊");
}
}
複製程式碼
對接微信支付的程式碼
package design.pattern;
public class WxPay {
/**
* start
*/
public void start() {
System.out.println("某種操作,我現在只是一個範例");
}
/**
* 介面鑑權
*/
public void auth() {
System.out.println("微信支付--生成sign校驗是否合法");
}
/**
* 向第三方下訂單
*/
public void thirdOrder() {
System.out.println("微信支付--下訂單介面");
}
/**
* 獲取支付平臺資訊
*/
public void getPayInfo() {
System.out.println("微信支付--獲取支付平臺資訊");
}
}
複製程式碼
客戶端呼叫:
//支付寶支付
AliPay aliPay = new AliPay();
aliPay.start();
aliPay.auth();
aliPay.thirdOrder();
aliPay.getPayInfo();
//微信支付
WxPay wxPay = new WxPay();
wxPay.start();
wxPay.auth();
wxPay.thirdOrder();
wxPay.getPayInfo();
複製程式碼
通過上面的例子我們發現了這兩個類的程式碼其實有很多相似的地方,他們之間存在著重複性程式碼,如start方法。是先鑑權還是先下訂單,這種完全依靠業務方的呼叫順序。
我們用模版方法模式來優化下.
首先我們想到,先把一部分公用方法的供不同支付平臺共享,把呼叫順序的細節封裝起來。
公共基礎類(演算法類):
package design.pattern;
public abstract class Pay {
/**
* start
*/
public void start() {
System.out.println("某種操作,我現在只是一個範例");
}
abstract void auth();
abstract void thirdOrder();
abstract void getPayInfo();
//實現排程順序
public void templateMethod() {
//step1
start();
//step2
auth();
//step3
thirdOrder();
//step4
getPayInfo();
}
}
複製程式碼
對應的具體支付類:
package design.pattern;
public class AliPay extends Pay {
/**
* 介面鑑權
*/
public void auth() {
System.out.println("支付寶--生成sign校驗是否合法");
}
/**
* 向第三方下訂單
*/
public void thirdOrder() {
System.out.println("支付寶--下訂單介面");
}
/**
* 獲取支付平臺資訊
*/
public void getPayInfo() {
System.out.println("支付寶--獲取支付平臺資訊");
}
}
複製程式碼
業務方呼叫者:
AliPay aliPay = new AliPay();
aliPay.templateMethod();
WxPay wxPay = new WxPay();
wxPay.templateMethod();
複製程式碼
output:
某種操作,我現在只是一個範例
支付寶--生成sign校驗是否合法
支付寶--下訂單介面
支付寶--獲取支付平臺資訊
某種操作,我現在只是一個範例
微信支付--生成sign校驗是否合法
微信支付--下訂單介面
微信支付--獲取支付平臺資訊
複製程式碼
經過簡單的改造,pay基礎類只需要關注公共部分和呼叫順序就可以了,更加方便修改。而其餘的業務細節由子類來實現。
但是可能還有其他的情況,比如我想對某個流程做一些開關怎麼辦,那就需要用到了Hook.
支付基礎類
package design.pattern;
public abstract class Pay {
/**
* start
*/
public void start() {
System.out.println("某種操作,我現在只是一個範例");
}
abstract void auth();
abstract void thirdOrder();
abstract void getPayInfo();
public void templateMethod() {
//step1
start();
//step2
auth();
//step3
if (isOrderOpen()) {
thirdOrder();
}
//step4
getPayInfo();
}
/**
* 是否開啟訂單方式
*
* @return
*/
protected boolean isOrderOpen() {
return true;
}
}
複製程式碼
預設是開啟向第三方下訂單的,比如某個平臺不需要這個操作,就可以覆蓋isOrderOpen方法就可以了。
package design.pattern;
public class AliPay extends Pay {
/**
* 介面鑑權
*/
public void auth() {
System.out.println("支付寶--生成sign校驗是否合法");
}
/**
* 向第三方下訂單
*/
public void thirdOrder() {
System.out.println("支付寶--下訂單介面");
}
/**
* 獲取支付平臺資訊
*/
public void getPayInfo() {
System.out.println("支付寶--獲取支付平臺資訊");
}
protected boolean isOrderOpen() {
//todo
return false;
}
}
複製程式碼
衍生出來的好萊塢原則:
別呼叫(打電話給)我們,我們會呼叫(打電話給)你
這句話很霸道。。。
其實意思高層元件允許低層元件掛鉤到系統上,但是高層元件決定什麼和如何去使用這些低層元件.換句話說: 高層元件對待低層元件的方式就是“別呼叫我們,我們會呼叫你”。
總結: 上面提出的例子不一定適合這個模式,希望能夠理解模版方法模式的意思就好了。
簡要來說: 模版方法模式是通過把不變行為搬到了超類,去除了子類中的重複程式碼。
相似模式: 策略模式
參考資料: 《大話設計模式》、《Head First設計模式》
更多設計模式思考 內容關注公眾號哈: