Java中的模板模式说明与实现
作者:靖节先生
1. 模板模式概述
1.1 模板模式介绍
- 模板方法模式(Template Method Pattern),又叫模板模式(Template Pattern), 在一个抽象类公开定义了执行它的方法的模板。它的子类可以更需要重写方法实现,但可以成为典型类中定义的方式进行。
- 简单说,模板方法模式定义了一个操作中的算法的核心定义,而将一些步骤迟缓到子类中,模仿子类可以不改变一一个算法的结构,就可以重新定义该算法的部分特定步骤。
- 这些类型的设计模式属于行为型模式。
模板模式适用于通用步骤的操作,比如做菜,不管你是西红柿炒鸡蛋,还是土豆炖牛肉实现步骤都是一样的,备料,做菜,上菜。 再比如投放系统,不管你是投放巨量引擎,广点通还是百度,前期工作实现步骤也都是一样的,配置物料信息,构建投放对象,投放广告。
1.2 模板模式类图
对原理类图的说明-即(模板方法模式的角色及职责)
1.AbstractClass 抽象类, 类中实现了模板方法(template),定义了算法的骨架,具体子类需要去实现 其它的抽象方法。
2.ConcreteClass 实现抽象方法, 以完成算法中特点子类的步骤。
1.3 模板方法模式的注意事项和细节
- 基本思想是:算法只存在于一个地方,也就是在父类中,容易修改.需要修改算法时,只要修改父类的模板方 法或者已经实现的某些步骤,子类就会继承这些修改
- 实现了最大化代码复用.父类的模板方法和已实现的某些步骤会被子类继承而直接使用
- 既统一了算法,也提供了很大的灵活性.父类的模板方法确保了算法的结构保持不变,同时由子类提供部分步 骤的实现.
- 该模式的不足之处:每个不同的实现都需要一个子类实现,导致类的个数增加,使得系统更加庞大
- 一般模板方法都加上 final 关键字, 防止子类重写模板方法
- 模板方法模式使用场景:当要完成在某个过程,该过程要执行一系列步骤 ,这一系列的步骤基本相同,但其 个别步骤在实现时 可能不同,通常考虑用模板方法模式来处理
2. 模板模式实现
模板模式实现案例采用三种方式: 第一案例是做菜,无论做什么菜都是这三个步骤,备料,做菜,上菜,但是三个步骤都不相同,模板定义步骤流程,通过不同的子类继承抽象模板实现模板设计模式。
第二个案例是银行办理业务,无论办理什么业务都是取号,办理业务,评价。这里取号与评价都是相同的,各个子类只需要处理不同业务即可,通过不同的子类继承抽象模板实现模板设计模式。
第三个案例是银行办理业务的Java8函数式编程消费者模式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("准备西红柿鸡蛋..."); } @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(); } }
2.2 银行办理业务模板模式
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$"); } }
2.3 银行办理业务函数式编程改造
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")); } }
到此这篇关于Java中的模板模式说明与实现的文章就介绍到这了,更多相关Java模板模式实现内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!