深入解析Java的設(shè)計(jì)模式編程中的模板方法模式
定義:
定義一個(gè)操作中的算法的框架,而將一些步驟延遲到子類(lèi)中。使得子類(lèi)可以不改變一個(gè)算法的結(jié)構(gòu)即可重新定義該算法的某些特定步驟。
聽(tīng)起來(lái)好高端的樣子,我的理解:
1.父類(lèi)聲明了若干個(gè)抽象方法(基本方法)和若干個(gè)具體方法(模板方法)
2.抽象方法是一個(gè)算法(過(guò)程)的步驟,在子類(lèi)中實(shí)現(xiàn)
3.模板方法是一個(gè)算法(過(guò)程)的框架,在父類(lèi)中已經(jīng)約定好,實(shí)現(xiàn)對(duì)基本方法調(diào)用,完成固定的邏輯
4.一個(gè)算法(過(guò)程)的結(jié)構(gòu)在父類(lèi)中定義,具體的實(shí)現(xiàn)細(xì)節(jié)則在子類(lèi)中實(shí)現(xiàn)
注:為了防止惡意操作,一般模板方法都加上final,禁止重寫(xiě)
通用類(lèi)圖:

事實(shí)上,模版方法是編程中一個(gè)經(jīng)常用到的模式。先來(lái)看一個(gè)例子,某日,程序員A拿到一個(gè)任務(wù):給定一個(gè)整數(shù)數(shù)組,把數(shù)組中的數(shù)由小到大排序,然后把排序之后的結(jié)果打印出來(lái)。經(jīng)過(guò)分析之后,這個(gè)任務(wù)大體上可分為兩部分,排序和打印,打印功能好實(shí)現(xiàn),排序就有點(diǎn)麻煩了。但是A有辦法,先把打印功能完成,排序功能另找人做。
abstract class AbstractSort {
/**
* 將數(shù)組array由小到大排序
* @param array
*/
protected abstract void sort(int[] array);
public void showSortResult(int[] array){
this.sort(array);
System.out.print("排序結(jié)果:");
for (int i = 0; i < array.length; i++){
System.out.printf("%3s", array[i]);
}
}
}
寫(xiě)完后,A找到剛畢業(yè)入職不久的同事B說(shuō):有個(gè)任務(wù),主要邏輯我已經(jīng)寫(xiě)好了,你把剩下的邏輯實(shí)現(xiàn)一下吧。于是把AbstractSort類(lèi)給B,讓B寫(xiě)實(shí)現(xiàn)。B拿過(guò)來(lái)一看,太簡(jiǎn)單了,10分鐘搞定,代碼如下:
class ConcreteSort extends AbstractSort {
@Override
protected void sort(int[] array){
for(int i=0; i<array.length-1; i++){
selectSort(array, i);
}
}
private void selectSort(int[] array, int index) {
int MinValue = 32767; // 最小值變量
int indexMin = 0; // 最小值索引變量
int Temp; // 暫存變量
for (int i = index; i < array.length; i++) {
if (array[i] < MinValue){ // 找到最小值
MinValue = array[i]; // 儲(chǔ)存最小值
indexMin = i;
}
}
Temp = array[index]; // 交換兩數(shù)值
array[index] = array[indexMin];
array[indexMin] = Temp;
}
}
寫(xiě)好后交給A,A拿來(lái)一運(yùn)行:
public class Client {
public static int[] a = { 10, 32, 1, 9, 5, 7, 12, 0, 4, 3 }; // 預(yù)設(shè)數(shù)據(jù)數(shù)組
public static void main(String[] args){
AbstractSort s = new ConcreteSort();
s.showSortResult(a);
}
}
運(yùn)行結(jié)果:
排序結(jié)果: 0 1 3 4 5 7 9 10 12 32
模版方法模式的結(jié)構(gòu)
模版方法模式由一個(gè)抽象類(lèi)和一個(gè)(或一組)實(shí)現(xiàn)類(lèi)通過(guò)繼承結(jié)構(gòu)組成,抽象類(lèi)中的方法分為三種:
抽象方法:父類(lèi)中只聲明但不加以實(shí)現(xiàn),而是定義好規(guī)范,然后由它的子類(lèi)去實(shí)現(xiàn)。
模版方法:由抽象類(lèi)聲明并加以實(shí)現(xiàn)。一般來(lái)說(shuō),模版方法調(diào)用抽象方法來(lái)完成主要的邏輯功能,并且,模版方法大多會(huì)定義為final類(lèi)型,指明主要的邏輯功能在子類(lèi)中不能被重寫(xiě)。
鉤子方法:由抽象類(lèi)聲明并加以實(shí)現(xiàn)。但是子類(lèi)可以去擴(kuò)展,子類(lèi)可以通過(guò)擴(kuò)展鉤子方法來(lái)影響模版方法的邏輯。
抽象類(lèi)的任務(wù)是搭建邏輯的框架,通常由經(jīng)驗(yàn)豐富的人員編寫(xiě),因?yàn)槌橄箢?lèi)的好壞直接決定了程序是否穩(wěn)定性。
實(shí)現(xiàn)類(lèi)用來(lái)實(shí)現(xiàn)細(xì)節(jié)。抽象類(lèi)中的模版方法正是通過(guò)實(shí)現(xiàn)類(lèi)擴(kuò)展的方法來(lái)完成業(yè)務(wù)邏輯。只要實(shí)現(xiàn)類(lèi)中的擴(kuò)展方法通過(guò)了單元測(cè)試,在模版方法正確的前提下,整體功能一般不會(huì)出現(xiàn)大的錯(cuò)誤。
模板方法模式的優(yōu)點(diǎn):
1. 封裝不變部分,擴(kuò)展可變部分
2. 提取公共部分代碼,便于維護(hù)
3. 行為由父類(lèi)控制,子類(lèi)實(shí)現(xiàn)
模板方法模式的適用場(chǎng)景:
1. 多個(gè)子類(lèi)有公共方法,并且邏輯基本相同
2. 對(duì)復(fù)雜的算法,核心算法設(shè)計(jì)為模板方法,細(xì)節(jié)功能則由各個(gè)子類(lèi)實(shí)現(xiàn)
3. 重構(gòu)代碼
模板方法模式的擴(kuò)展
- 基本方法由于不需要對(duì)外提供訪問(wèn),因此可以設(shè)計(jì)為protected類(lèi)型
- 設(shè)計(jì)鉤子方法(Hook Method):對(duì)外部提供接口,可以影響模板方法內(nèi)的具體執(zhí)行順序
總結(jié):
父類(lèi)建立框架,子類(lèi)在重寫(xiě)了父類(lèi)部分方法后,再調(diào)用從父類(lèi)繼承的方法,產(chǎn)生不同的結(jié)果。
相關(guān)文章
Mybatis-Plus3.x的創(chuàng)建步驟及使用教程
MyBatis-Plus是一個(gè)?MyBatis?的增強(qiáng)工具,在?MyBatis?的基礎(chǔ)上只做增強(qiáng)不做改變,為?簡(jiǎn)化開(kāi)發(fā)、提高效率而生,這篇文章主要介紹了Mybatis-Plus3.x的使用,需要的朋友可以參考下2023-10-10
java求100之內(nèi)的素?cái)?shù)(質(zhì)數(shù))簡(jiǎn)單示例
這篇文章主要介紹了java求100之內(nèi)的素?cái)?shù)簡(jiǎn)單示例,素?cái)?shù)是一個(gè)大于1的自然數(shù),如果除了1和它自身外,不能被其他自然數(shù)整除的數(shù);否則稱(chēng)為合數(shù)2014-04-04
Hibernate用ThreadLocal模式(線程局部變量模式)管理Session
今天小編就為大家分享一篇關(guān)于Hibernate用ThreadLocal模式(線程局部變量模式)管理Session,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-03-03
深入解析Java的Hibernate框架中的持久對(duì)象
Hibernate的持久對(duì)象在數(shù)據(jù)庫(kù)數(shù)據(jù)操作中有著重要作用,這里我們就來(lái)深入解析Java的Hibernate框架中的持久對(duì)象,首先必須從理解持久化對(duì)象的生命周期開(kāi)始:2016-07-07
Java中Stream流的peek方法詳解及常見(jiàn)使用場(chǎng)景
這篇文章主要介紹了Java中Stream流的peek方法詳解及常見(jiàn)使用場(chǎng)景的相關(guān)資料,peek()方法是一個(gè)中間操作,用于在流的每個(gè)元素上執(zhí)行一個(gè)操作,而不會(huì)改變流中的元素或中斷流的處理,需要的朋友可以參考下2025-03-03
詳解java8在Collection中新增加的方法removeIf
這篇文章主要介紹了詳解java8在Collection中新增加的方法removeIf的相關(guān)資料,需要的朋友可以參考下2018-01-01

