1.模板方法模式(Template Method Pattern),又叫模板模式(Template Pattern), 在一个抽象类公开定义了执行它的方法的模板。它的子类可以更需要重写方法实现,但可以成为典型类中定义的方式进行。
2.简单说,模板方法模式定义了一个操作中的算法的核心定义,而将一些步骤迟缓到子类中,模仿子类可以不改变一一个算法的结构,就可以重新定义该算法的部分特定步骤。
3.这些类型的设计模式属于行为型模式。
模板模式适用于通用步骤的操作,比如做菜,不管你是西红柿炒鸡蛋,还是土豆炖牛肉实现步骤都是一样的,备料,做菜,上菜。
再比如投放系统,不管你是投放巨量引擎,广点通还是百度,前期工作实现步骤也都是一样的,配置物料信息,构建投放对象,投放广告。
对原理类图的说明-即(模板方法模式的角色及职责)
1.AbstractClass 抽象类, 类中实现了模板方法(template),定义了算法的骨架,具体子类需要去实现 其它的抽象方法。
2.ConcreteClass 实现抽象方法, 以完成算法中特点子类的步骤。
模板模式实现案例采用三种方式:
第一案例是做菜,无论做什么菜都是这三个步骤,备料,做菜,上菜,但是三个步骤都不相同,模板定义步骤流程,通过不同的子类继承抽象模板实现模板设计模式。
第二个案例是银行办理业务,无论办理什么业务都是取号,办理业务,评价。这里取号与评价都是相同的,各个子类只需要处理不同业务即可,通过不同的子类继承抽象模板实现模板设计模式。
第三个案例是银行办理业务的Java8函数式编程消费者模式Consumer模式改造,原理相同。
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("准备西红柿鸡蛋...");
}
@Override
public void doing() {
System.out.println("开始炒西红柿鸡蛋...");
}
@Override
public void carriedDishes() {
System.out.println("西红柿鸡蛋装盘...");
}
}
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("准备小葱豆腐...");
}
@Override
public void doing() {
System.out.println("开始炒小葱拌豆腐...");
}
@Override
public void carriedDishes() {
System.out.println("小葱拌豆腐装盘...");
}
}
DishTemplate
package com.zrj.design.template.dish;
/**
* 做菜模板类
* 用于定义做菜的执行步骤,所有菜都可以按照这种方式做菜
*
* @author zrj
* @since 2022/2/8
*/
public abstract class DishTemplate {
/**
* 做菜执行步骤
*/
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;
/**
* 模板模式
* 抽象父类定义方法模板,子类自定义实现方式。
* 优点: 1、封装不变部分,扩展可变部分。 2、提取公共代码,便于维护。 3、行为由父类控制,子类实现。
* 缺点:每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。
* 使用场景: 1、有多个子类共有的方法,且逻辑相同。 2、重要的、复杂的方法,可以考虑作为模板方法。
* 注意事项:为防止恶意操作,一般模板方法都加上 final 关键词。
*
* 使用场景很多,只要有相同的执行逻辑,或者重要的复杂的方法,都可以交给父类管理。
* 比如开发XX系统步骤都是一样的,立项,需求,开发,测试,上线。
*
* @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();
}
}
BankBusinessHandler
package com.zrj.design.template.bank;
import cn.hutool.core.util.RandomUtil;
/**
* 模板方法设计模式的抽象类
* 模板设计模式主要用来处理相同处理流程中的不同点,例如银行办理业务,无论什么业务,首先需要取号,其次处理业务,然后评价不同之处在于处理不同的业务使用不同的方式。
* BankBusinessHandler作为抽象模板
* BankSaveMoneyHandler作为存钱业务处理类,继承抽象模板BankBusinessHandler
* BankDrawMoneyHandler作为理财业务处理类,继承抽象模板BankBusinessHandler
*
* @author zrj
* @since 2022/2/8
**/
public abstract class BankBusinessHandler {
/**
* 模板方法,执行器
*/
public final void execute() {
getNumber();
handle();
judge();
}
/**
* 取号
*/
private void getNumber() {
System.out.println("取号:" + RandomUtil.randomNumbers(8));
}
/**
* 办理业务
*/
public abstract void handle();
/**
* 评价
*/
private void judge() {
System.out.println("评价:五星好评!");
}
}
BankBusinessHandlerTest
package com.zrj.design.template.bank;
/**
* 模板方法测试类
*
* @author zrj
* @since 2022/2/8
**/
public class BankBusinessHandlerTest {
public static void main(String[] args) {
//存钱业务处理
BankSaveMoneyHandler bankSaveMoneyHandler = new BankSaveMoneyHandler();
bankSaveMoneyHandler.execute();
System.out.println("------------------------------");
//理财业务处理
BankDrawMoneyHandler bankDrawMoneyHandler = new BankDrawMoneyHandler();
bankDrawMoneyHandler.execute();
}
}
BankDrawMoneyHandler
package com.zrj.design.template.bank;
/**
* 理财业务
*
* @author zrj
* @since 2022/2/8
**/
public class BankDrawMoneyHandler extends BankBusinessHandler {
/**
* 办理业务
*/
@Override
public void handle() {
System.out.println("理财:2000$");
}
}
BankSaveMoneyHandler
package com.zrj.design.template.bank;
/**
* 存钱业务
*
* @author zrj
* @since 2022/2/8
**/
public class BankSaveMoneyHandler extends BankBusinessHandler {
/**
* 办理业务
*/
@Override
public void handle() {
System.out.println("存钱:1000$");
}
}
BankBusinessHandlerCustomer
package com.zrj.design.template.customer;
import cn.hutool.core.util.RandomUtil;
import java.math.BigDecimal;
import java.util.function.Consumer;
/**
* 模板设计模式的抽象类
* Java8函数式编程消费者模式Customer实现模板设计模式
*
* @author zrj
* @since 2022/2/8
**/
public class BankBusinessHandlerCustomer {
/**
* 存钱
*/
public void save(BigDecimal amount) {
execute(a -> System.out.println("存钱:" + amount));
}
/**
* 理财
*/
public void draw(BigDecimal amount) {
execute(a -> System.out.println("理财:" + amount));
}
/**
* 模板方法,执行器
*/
public void execute(Consumer<BigDecimal> consumer) {
getNumber();
consumer.accept(null);
judge();
}
/**
* 取号
*/
private void getNumber() {
System.out.println("取号:" + RandomUtil.randomNumbers(8));
}
/**
* 评价
*/
private void judge() {
System.out.println("评价:五星好评!");
}
}
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) {
//构建银行业务处理对象
BankBusinessHandlerCustomer businessHandler = new BankBusinessHandlerCustomer();
//存钱业务处理
businessHandler.save(new BigDecimal("3000"));
System.out.println("------------------------------");
//理财业务处理
businessHandler.draw(new BigDecimal("6000"));
}
}