#### 模板模式的定義 其定義如下: Define the skeleton of an algorithm in an operation,deferring some steps to subclasses.Template Method lets subclasses redefine ce ...
模板模式的定義
其定義如下:
Define the skeleton of an algorithm in an operation,deferring some steps to subclasses.Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.(定義一個操作中的演算法的框架,而將一些步驟延遲到子類中。使得子類可以不改變一個演算法的結構即可重定義該演算法的某些特定步驟。)
模板模式通用類圖
模板模式通用代碼
抽象模板類
public abstract class AbstractClass {
//基本方法
protected abstract void doSomething();
//基本方法
protected abstract void doAnything();
//模板方法
public void templateMethod(){
/*
* 調用基本方法,完成相關的邏輯
*/
this.doAnything();
this.doSomething();
}
}
具體模板類
public class ConcreteClass1 extends AbstractClass {
//實現基本方法
protected void doAnything() {
//業務邏輯處理
}
protected void doSomething() {
//業務邏輯處理
}
}
public class ConcreteClass2 extends AbstractClass {
//實現基本方法
protected void doAnything() {
//業務邏輯處理
}
protected void doSomething() {
//業務邏輯處理
}
}
場景類
public class Client {
public static void main(String[] args) {
AbstractClass class1 = new ConcreteClass1();
AbstractClass class2 = new ConcreteClass2();
//調用模板方法
class1.templateMethod();
class2.templateMethod();
}
}
模板模式的優點
- 封裝不變部分,擴展可變部分。
把認為是不變部分的演算法封裝到父類實現,而可變部分的則可以通過繼承來繼續擴展。 - 提取公共部分代碼,便於維護。
- 行為由父類控制,子類實現。
基本方法是由子類實現的,因此子類可以通過擴展的方式增加相應的功能,符合開閉原則。
模板方法模式的缺點
按照我們的設計習慣,抽象類負責聲明最抽象、最一般的事物屬性和方法,實現類完成具體的事物屬性和方法。但是模板方法模式卻顛倒了,抽象類定義了部分抽象方法,由子類實現,子類執行的結果影響了父類的結果,也就是子類對父類產生了影響,這在複雜的項目中,會帶來代碼閱讀的難度,而且也會讓新手產生不適感。
模板方法模式的使用場景
● 多個子類有公有的方法,並且邏輯基本相同時。
● 重要、複雜的演算法,可以把核心演算法設計為模板方法,周邊的相關細節功能則由各個子類實現。
● 重構時,模板方法模式是一個經常使用的模式,把相同的代碼抽取到父類中,然後通過鉤子函數(見“模板方法模式的擴展”)約束其行為。
場景示例
我現在有這麼一個業務,醫院每次病人看病,繳費都有這麼一個大概的流程 構建訂單->病人支付->系統處理支付的業務邏輯。
因為支付業務是可以分多種的,比如掛號繳費,門診繳費,構建訂單和病人支付的流程都是不變的,針對不同的類型的繳費業務,繳費完成後系統需要處理不同的業務邏輯。現在可以使用模板模式編寫代碼。
抽象模板類
/**
* 就診模板
*/
public abstract class VisitProcessTemplate {
/**
* 構建訂單
*/
public void initOrder(){
System.out.println("構建訂單");
}
/**
* 支付
*/
public void orderPay(){
System.out.println("訂單支付");
}
/**
* 處理下單之後的業務邏輯
*/
public abstract void payOk();
/**
* 就診流程
*/
public void visitRun(){
initOrder();
orderPay();
payOk();
}
}
掛號具體模板類
public class RegisterVisitProcess extends VisitProcessTemplate{
@Override
public void payOk() {
System.out.println("支付成功,處理病人掛號業務");
}
}
門診繳費具體模板類
public class OutpatientVisitProcess extends VisitProcessTemplate{
@Override
public void payOk() {
System.out.println("支付成功,處理病人門診繳費業務");
}
}
場景類
public class Client {
public static void main(String[] args) {
VisitProcessTemplate visitProcessTemplate = new OutpatientVisitProcess();
VisitProcessTemplate visitProcessTemplate1 = new RegisterVisitProcess();
visitProcessTemplate.visitRun();
visitProcessTemplate1.visitRun();
}
}
模板方法模式的擴展(鉤子函數)
假如我現在新增了一個業務,這個業務是醫院診療卡辦理服務,這個業務是免費的,病人無需費用就可以辦卡,可別的業務又需要支付,該怎麼優化這段代碼呢?使用鉤子函數。
優化後的就診模板
/**
* 就診模板
*/
public abstract class VisitProcessTemplate {
/**
* 構建訂單
*/
public void initOrder(){
System.out.println("構建訂單");
}
/**
* 支付
*/
public void orderPay(){
System.out.println("訂單支付");
}
/**
* 處理下單之後的業務邏輯
*/
public abstract void payOk();
/**
* 鉤子函數,預設需要支付
*/
public boolean needPay(){
return true;
}
/**
* 就診流程
*/
public void visitRun(){
initOrder();
if (needPay()){
orderPay();
}
payOk();
}
}
辦卡具體模板類
public class CardVisitProcess extends VisitProcessTemplate{
@Override
public void payOk() {
System.out.println("處理病人辦卡業務");
}
@Override
public boolean needPay() {
return false;
}
}