(一)需求場景
現實生活中,我們會遇到很多時候一些具有特定步驟和流程的事項,比如紙張打印:準備紙張,操作機器,開始打印,結束打印;又或者是製作豆漿牛奶:選材,添加配料,放到豆漿機攪拌;燒菜:準備食材,開火,烹飪,關火等等,這樣的案例數不勝數.它們都有着一定的共性,即使有着相近的步驟,但是由於初始條件和參數等不同,就可以產生不同的結果,食材的不同,烹飪方法的不同都會做出不同的菜品.
(二)基本介紹
模板方法模式(Template Method Pattern),又叫模板模式(Template Pattern.它就是根據這些特性總結出的一種模式,一個抽象類公開定義了執行它的方法的方式/模板。它的子類可以按需要重寫方法實現,但調用將以抽象類中定義的方式進行。這種類型的設計模式屬於行爲型模式。
(三)工作原理
1:通過抽象父類模板方法定義總體流程和算法骨架,而由具體的子類去完成各自細節部分的不同實現.
2:AbstractClass 抽象類, 類中實現了模板方法(template),定義了算法的骨架,具體子類需要去實現
3:ConcreteClass 實現各個抽象方法 以完成算法中特點子類的步驟
4:這種設計模式由模板方法完成具體算法設計和架構,子類只負責步驟實現,如果需要進行改動,只要改動模板方法即可
5:模板模式中模板方法一般由final修飾,避免在子類中進行改動
6:模板模式在使用過程中,實例是保存在父類中,即返回類型爲父類,這樣的好處在於即使沒有用instanceof指定子類的種類,程序也能夠正常工作.無論父類類型中的變量保存的是那個子類的實例,程序都可以正常工作,這種原則稱爲裏式替換原則(LSP)
(四)代碼實例
本次實例模擬爲做菜的模板流程,AbstractCooking 定義了燒菜的幾個步驟,然後設定模板方法cooking定義做菜的算法框架,由子類實現,完成各自不同的菜品燒製
/**
* 模板抽象類
* 模板方法算法:打開開關,烹飪,關閉電源開關
**/
public abstract class AbstractCooking {
final void cooking() {
//在父類中定義算法結構骨架
open();
mixFood();
close();
}
//開啓電源
abstract void open();
//混合攪拌
abstract void mixFood();
//關閉電源
abstract void close();
}
public class BraisedFish extends AbstractCooking {
@Override
void open() {
System.out.println("開啓電源");
}
@Override
void mixFood() {
System.out.println("正在烹飪紅燒魚...");
}
@Override
void close() {
System.out.println("關閉電源");
}
}
public class EggSoup extends AbstractCooking {
@Override
void open() {
System.out.println("開啓電源");
}
@Override
void mixFood() {
System.out.println("正在煮雞蛋湯...");
}
@Override
void close() {
System.out.println("關閉電源");
}
}
public class Main {
public static void main(String[] args) {
AbstractCooking braisedFish = new BraisedFish();
braisedFish.cooking();
AbstractCooking eggSoup = new EggSoup();
eggSoup.cooking();
}
}
(五)應用實例
1:spring 中對 Hibernate 的支持,將一些已經定好的方法封裝起來,比如開啓事務、獲取 Session、關閉 Session 等,程序員不重複寫那些已經規範好的代碼,直接丟一個實體就可以保存
2:java.io.InputStream, java.io.OutputStream, java.io.Reader 以及 java.io.Writer 中所有非抽象方法 . 這幾個類都是抽象類,而且有不同類型流的子類實現,但是其中的幾個非抽象方法,例如:InputStream.read()和OutputStream.write()都使用了模板方法模式,不需要子類去實現具體算法邏輯,父類提供算法骨架設計.
3:Spring IOC容器初始化時運用到的模板方法模式
在閱讀Spring源碼的時候,我們肯定會看到這一個方法refresh(),該方法是完成IOC初始化的主要功能實現,包括循環依賴,Bean解析和定義等等.該方法就是一種模板方法實現.其中在ConfigurableApplicationContext 接口中定義該方法
public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
void refresh() throws BeansException, IllegalStateException;
}
AbstractApplicationContext 抽象類實現了ConfigurableApplicationContext接口,並實現了refresh方法,其中基本上完成了IOC初始化的算法設計和架構,定義了模板方法架構設計.而它的子類不需要在重寫該方法,只需要完成各自實現的步驟即可,總體的流程由父類來完成
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext, DisposableBean {
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//省略
}
}
}