Java中的模板模式說(shuō)明與實(shí)現(xiàn)
1. 模板模式概述
1.1 模板模式介紹
- 模板方法模式(Template Method Pattern),又叫模板模式(Template Pattern), 在一個(gè)抽象類(lèi)公開(kāi)定義了執(zhí)行它的方法的模板。它的子類(lèi)可以更需要重寫(xiě)方法實(shí)現(xiàn),但可以成為典型類(lèi)中定義的方式進(jìn)行。
- 簡(jiǎn)單說(shuō),模板方法模式定義了一個(gè)操作中的算法的核心定義,而將一些步驟遲緩到子類(lèi)中,模仿子類(lèi)可以不改變一一個(gè)算法的結(jié)構(gòu),就可以重新定義該算法的部分特定步驟。
- 這些類(lèi)型的設(shè)計(jì)模式屬于行為型模式。
模板模式適用于通用步驟的操作,比如做菜,不管你是西紅柿炒雞蛋,還是土豆燉牛肉實(shí)現(xiàn)步驟都是一樣的,備料,做菜,上菜。 再比如投放系統(tǒng),不管你是投放巨量引擎,廣點(diǎn)通還是百度,前期工作實(shí)現(xiàn)步驟也都是一樣的,配置物料信息,構(gòu)建投放對(duì)象,投放廣告。
1.2 模板模式類(lèi)圖

對(duì)原理類(lèi)圖的說(shuō)明-即(模板方法模式的角色及職責(zé))
1.AbstractClass 抽象類(lèi), 類(lèi)中實(shí)現(xiàn)了模板方法(template),定義了算法的骨架,具體子類(lèi)需要去實(shí)現(xiàn) 其它的抽象方法。
2.ConcreteClass 實(shí)現(xiàn)抽象方法, 以完成算法中特點(diǎn)子類(lèi)的步驟。
1.3 模板方法模式的注意事項(xiàng)和細(xì)節(jié)
- 基本思想是:算法只存在于一個(gè)地方,也就是在父類(lèi)中,容易修改.需要修改算法時(shí),只要修改父類(lèi)的模板方 法或者已經(jīng)實(shí)現(xiàn)的某些步驟,子類(lèi)就會(huì)繼承這些修改
- 實(shí)現(xiàn)了最大化代碼復(fù)用.父類(lèi)的模板方法和已實(shí)現(xiàn)的某些步驟會(huì)被子類(lèi)繼承而直接使用
- 既統(tǒng)一了算法,也提供了很大的靈活性.父類(lèi)的模板方法確保了算法的結(jié)構(gòu)保持不變,同時(shí)由子類(lèi)提供部分步 驟的實(shí)現(xiàn).
- 該模式的不足之處:每個(gè)不同的實(shí)現(xiàn)都需要一個(gè)子類(lèi)實(shí)現(xiàn),導(dǎo)致類(lèi)的個(gè)數(shù)增加,使得系統(tǒng)更加龐大
- 一般模板方法都加上 final 關(guān)鍵字, 防止子類(lèi)重寫(xiě)模板方法
- 模板方法模式使用場(chǎng)景:當(dāng)要完成在某個(gè)過(guò)程,該過(guò)程要執(zhí)行一系列步驟 ,這一系列的步驟基本相同,但其 個(gè)別步驟在實(shí)現(xiàn)時(shí) 可能不同,通常考慮用模板方法模式來(lái)處理
2. 模板模式實(shí)現(xiàn)
模板模式實(shí)現(xiàn)案例采用三種方式: 第一案例是做菜,無(wú)論做什么菜都是這三個(gè)步驟,備料,做菜,上菜,但是三個(gè)步驟都不相同,模板定義步驟流程,通過(guò)不同的子類(lèi)繼承抽象模板實(shí)現(xiàn)模板設(shè)計(jì)模式。
第二個(gè)案例是銀行辦理業(yè)務(wù),無(wú)論辦理什么業(yè)務(wù)都是取號(hào),辦理業(yè)務(wù),評(píng)價(jià)。這里取號(hào)與評(píng)價(jià)都是相同的,各個(gè)子類(lèi)只需要處理不同業(yè)務(wù)即可,通過(guò)不同的子類(lèi)繼承抽象模板實(shí)現(xiàn)模板設(shè)計(jì)模式。
第三個(gè)案例是銀行辦理業(yè)務(wù)的Java8函數(shù)式編程消費(fèi)者模式Consumer模式改造,原理相同。
2.1 做菜模板模式
DishEggsWithTomato
package com.zrj.design.template.dish;
/**
* 西紅柿炒雞蛋
*
* @author zrj
* @since 2022/2/8
*/
public class DishEggsWithTomato extends DishTemplate {
@Override
public void preparation() {
System.out.println("準(zhǔn)備西紅柿雞蛋...");
}
@Override
public void doing() {
System.out.println("開(kāi)始炒西紅柿雞蛋...");
}
@Override
public void carriedDishes() {
System.out.println("西紅柿雞蛋裝盤(pán)...");
}
}DishOnionWithTofu
package com.zrj.design.template.dish;
/**
* 小蔥拌豆腐
*
* @author zrj
* @since 2022/2/8
*/
public class DishOnionWithTofu extends DishTemplate {
@Override
public void preparation() {
System.out.println("準(zhǔn)備小蔥豆腐...");
}
@Override
public void doing() {
System.out.println("開(kāi)始炒小蔥拌豆腐...");
}
@Override
public void carriedDishes() {
System.out.println("小蔥拌豆腐裝盤(pán)...");
}
}DishTemplate
package com.zrj.design.template.dish;
/**
* 做菜模板類(lèi)
* 用于定義做菜的執(zhí)行步驟,所有菜都可以按照這種方式做菜
*
* @author zrj
* @since 2022/2/8
*/
public abstract class DishTemplate {
/**
* 做菜執(zhí)行步驟
*/
public final void doDish() {
this.preparation();
this.doing();
this.carriedDishes();
}
/**
* 備料
*/
public abstract void preparation();
/**
* 做菜
*/
public abstract void doing();
/**
* 上菜
*/
public abstract void carriedDishes();
}DishTemplateTest
package com.zrj.design.template.dish;
import org.junit.Test;
/**
* 模板模式
* 抽象父類(lèi)定義方法模板,子類(lèi)自定義實(shí)現(xiàn)方式。
* 優(yōu)點(diǎn): 1、封裝不變部分,擴(kuò)展可變部分。 2、提取公共代碼,便于維護(hù)。 3、行為由父類(lèi)控制,子類(lèi)實(shí)現(xiàn)。
* 缺點(diǎn):每一個(gè)不同的實(shí)現(xiàn)都需要一個(gè)子類(lèi)來(lái)實(shí)現(xiàn),導(dǎo)致類(lèi)的個(gè)數(shù)增加,使得系統(tǒng)更加龐大。
* 使用場(chǎng)景: 1、有多個(gè)子類(lèi)共有的方法,且邏輯相同。 2、重要的、復(fù)雜的方法,可以考慮作為模板方法。
* 注意事項(xiàng):為防止惡意操作,一般模板方法都加上 final 關(guān)鍵詞。
*
* 使用場(chǎng)景很多,只要有相同的執(zhí)行邏輯,或者重要的復(fù)雜的方法,都可以交給父類(lèi)管理。
* 比如開(kāi)發(fā)XX系統(tǒng)步驟都是一樣的,立項(xiàng),需求,開(kāi)發(fā),測(cè)試,上線。
*
* @author zrj
* @since 2022/2/8
*/
public class DishTemplateTest {
@Test
public void templateTest() {
System.out.println("----------西紅柿炒雞蛋----------");
DishTemplate eggsWithTomato = new DishEggsWithTomato();
eggsWithTomato.doDish();
System.out.println("----------小蔥拌豆腐----------");
DishTemplate onionWithTofu = new DishOnionWithTofu();
onionWithTofu.doDish();
}
}2.2 銀行辦理業(yè)務(wù)模板模式
BankBusinessHandler
package com.zrj.design.template.bank;
import cn.hutool.core.util.RandomUtil;
/**
* 模板方法設(shè)計(jì)模式的抽象類(lèi)
* 模板設(shè)計(jì)模式主要用來(lái)處理相同處理流程中的不同點(diǎn),例如銀行辦理業(yè)務(wù),無(wú)論什么業(yè)務(wù),首先需要取號(hào),其次處理業(yè)務(wù),然后評(píng)價(jià)不同之處在于處理不同的業(yè)務(wù)使用不同的方式。
* BankBusinessHandler作為抽象模板
* BankSaveMoneyHandler作為存錢(qián)業(yè)務(wù)處理類(lèi),繼承抽象模板BankBusinessHandler
* BankDrawMoneyHandler作為理財(cái)業(yè)務(wù)處理類(lèi),繼承抽象模板BankBusinessHandler
*
* @author zrj
* @since 2022/2/8
**/
public abstract class BankBusinessHandler {
/**
* 模板方法,執(zhí)行器
*/
public final void execute() {
getNumber();
handle();
judge();
}
/**
* 取號(hào)
*/
private void getNumber() {
System.out.println("取號(hào):" + RandomUtil.randomNumbers(8));
}
/**
* 辦理業(yè)務(wù)
*/
public abstract void handle();
/**
* 評(píng)價(jià)
*/
private void judge() {
System.out.println("評(píng)價(jià):五星好評(píng)!");
}
}BankBusinessHandlerTest
package com.zrj.design.template.bank;
/**
* 模板方法測(cè)試類(lèi)
*
* @author zrj
* @since 2022/2/8
**/
public class BankBusinessHandlerTest {
public static void main(String[] args) {
//存錢(qián)業(yè)務(wù)處理
BankSaveMoneyHandler bankSaveMoneyHandler = new BankSaveMoneyHandler();
bankSaveMoneyHandler.execute();
System.out.println("------------------------------");
//理財(cái)業(yè)務(wù)處理
BankDrawMoneyHandler bankDrawMoneyHandler = new BankDrawMoneyHandler();
bankDrawMoneyHandler.execute();
}
}BankDrawMoneyHandler
package com.zrj.design.template.bank;
/**
* 理財(cái)業(yè)務(wù)
*
* @author zrj
* @since 2022/2/8
**/
public class BankDrawMoneyHandler extends BankBusinessHandler {
/**
* 辦理業(yè)務(wù)
*/
@Override
public void handle() {
System.out.println("理財(cái):2000$");
}
}BankSaveMoneyHandler
package com.zrj.design.template.bank;
/**
* 存錢(qián)業(yè)務(wù)
*
* @author zrj
* @since 2022/2/8
**/
public class BankSaveMoneyHandler extends BankBusinessHandler {
/**
* 辦理業(yè)務(wù)
*/
@Override
public void handle() {
System.out.println("存錢(qián):1000$");
}
}2.3 銀行辦理業(yè)務(wù)函數(shù)式編程改造
BankBusinessHandlerCustomer
package com.zrj.design.template.customer;
import cn.hutool.core.util.RandomUtil;
import java.math.BigDecimal;
import java.util.function.Consumer;
/**
* 模板設(shè)計(jì)模式的抽象類(lèi)
* Java8函數(shù)式編程消費(fèi)者模式Customer實(shí)現(xiàn)模板設(shè)計(jì)模式
*
* @author zrj
* @since 2022/2/8
**/
public class BankBusinessHandlerCustomer {
/**
* 存錢(qián)
*/
public void save(BigDecimal amount) {
execute(a -> System.out.println("存錢(qián):" + amount));
}
/**
* 理財(cái)
*/
public void draw(BigDecimal amount) {
execute(a -> System.out.println("理財(cái):" + amount));
}
/**
* 模板方法,執(zhí)行器
*/
public void execute(Consumer<BigDecimal> consumer) {
getNumber();
consumer.accept(null);
judge();
}
/**
* 取號(hào)
*/
private void getNumber() {
System.out.println("取號(hào):" + RandomUtil.randomNumbers(8));
}
/**
* 評(píng)價(jià)
*/
private void judge() {
System.out.println("評(píng)價(jià):五星好評(píng)!");
}
}BankBusinessHandlerCustomerTest
package com.zrj.design.template.customer;
import java.math.BigDecimal;
/**
* @author zrj
* @since 2022/2/8
**/
public class BankBusinessHandlerCustomerTest {
public static void main(String[] args) {
//構(gòu)建銀行業(yè)務(wù)處理對(duì)象
BankBusinessHandlerCustomer businessHandler = new BankBusinessHandlerCustomer();
//存錢(qián)業(yè)務(wù)處理
businessHandler.save(new BigDecimal("3000"));
System.out.println("------------------------------");
//理財(cái)業(yè)務(wù)處理
businessHandler.draw(new BigDecimal("6000"));
}
}到此這篇關(guān)于Java中的模板模式說(shuō)明與實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Java模板模式實(shí)現(xiàn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java數(shù)據(jù)結(jié)構(gòu)學(xué)習(xí)之樹(shù)
這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)學(xué)習(xí)之樹(shù),文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java數(shù)據(jù)結(jié)構(gòu)的小伙伴們有非常好的幫助,需要的朋友可以參考下2021-05-05
springBoot接入阿里云oss的實(shí)現(xiàn)步驟
這篇文章主要介紹了springBoot接入阿里云oss的實(shí)現(xiàn)步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01
Java利用MD5加鹽實(shí)現(xiàn)對(duì)密碼進(jìn)行加密處理
在開(kāi)發(fā)的時(shí)候,有一些敏感信息是不能直接通過(guò)明白直接保存到數(shù)據(jù)庫(kù)的。最經(jīng)典的就是密碼了。如果直接把密碼以明文的形式入庫(kù),不僅會(huì)泄露用戶的隱私,對(duì)系統(tǒng)也是極其的不厲。本文就來(lái)和大家介紹一下如何對(duì)密碼進(jìn)行加密處理,感興趣的可以了解一下2023-02-02
mybatisPlus填坑之邏輯刪除的實(shí)現(xiàn)
本文主要介紹了mybatisPlus填坑之邏輯刪除的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01
struts2與cookie 實(shí)現(xiàn)自動(dòng)登錄和驗(yàn)證碼驗(yàn)證實(shí)現(xiàn)代碼
這篇文章主要介紹了struts2與cookie 實(shí)現(xiàn)自動(dòng)登錄和驗(yàn)證碼驗(yàn)證實(shí)現(xiàn)代碼的相關(guān)資料,需要的朋友可以參考下2016-10-10
java中FileOutputStream中文亂碼問(wèn)題解決辦法
這篇文章主要介紹了java中FileOutputStream中文亂碼問(wèn)題解決辦法的相關(guān)資料,需要的朋友可以參考下2017-04-04
記一次用IDEA打開(kāi)java項(xiàng)目后不能運(yùn)行的解決方法
這篇文章主要介紹了記一次用IDEA打開(kāi)java項(xiàng)目后不能運(yùn)行的解決方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03
Java?Chassis3熔斷機(jī)制的改進(jìn)路程技術(shù)解密
這篇文章主要介紹了Java?Chassis?3技術(shù)解密之熔斷機(jī)制的改進(jìn)路程實(shí)例分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01
Gson中@JsonAdater注解的幾種方式總結(jié)
這篇文章主要介紹了Gson中@JsonAdater注解的幾種方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08

