概念
https://www.runoob.com/design-pattern/template-pattern.html
模板方法设计模式是行为型设计模式中的一种,用在一个功能的完成需要经过一系列步骤, 这些步骤是固定的,但是中间某些步骤具体行为是待定的,在不同的场景中行为不同, 此时就可以考虑使用模板方法设计模式来完成,不同的场景对应不同的子类实现。
模板方法包含如下的角色:
抽象类/抽象模板(Abstract Class):负责给出一个算法的轮廓,由一个模板方法和若干个基本方法构成, 这些方法定义如下 1:模板方法(该方法也正是模式的核心),定义算法的框架,按照某种顺序调用其中的基本方法。 2:基本方法,可以包含如下的几种类型 抽象方法:由具体的子类实现,作为定制行为,因为是抽象方法所以子类必须实现。 具体方法:在抽象类中已经提供了具体的实现,子类可以继承或者重写(按照里氏替换原则, 最好不要重写)。 钩子方法:在抽象类中已经提供了实现(一般是空实现),类似于抽象方法,但是并非强制 子类实现,因为已经提供了默认实现,可以在需要进行能力扩展时使用。 具体子类/具体实现(Concrete Class):必须实现抽象模板中的抽象方法,以及选择性的重载钩子方法。
定义一个模板接口
public interface Cookingtemplate { void buySth(); void washFood(); void cook(); void eat(); String make(); }
实现模板接口
@Slf4j @Service public class CookingFruitImpl implements Cookingtemplate { @Override public String make() { buySth(); washFood(); cook(); eat(); return "水果大餐"; } @Override public void buySth() { log.info("买些苹果,芒果,香蕉,水蜜桃"); } @Override public void washFood() { log.info("把水果洗干净"); } @Override public void cook() { log.info("放点沙拉酱做水果沙拉"); } @Override public void eat() { log.info("享用水果沙拉"); } }
@Slf4j @Service public class CookingVegetableImpl implements Cookingtemplate { @Override public String make() { buySth(); washFood(); cook(); eat(); return "蔬菜大餐"; } @Override public void buySth() { log.info("买些菠菜,土豆,西红柿"); } @Override public void washFood() { log.info("把蔬菜洗干净"); } @Override public void cook() { log.info("做个西红柿炒土豆丝,炒个菠菜"); } @Override public void eat() { log.info("享用小炒"); } }
定义枚举类将食物类型与烹饪模板实现类关联起来
/** * 做饭枚举 */ public enum CookingEnum { /** * 蔬菜实现类枚举 */ VEGETABLE("vegetable","cookingVegetableImpl"), /** * 水果实现类枚举 */ FRUIT("fruit","cookingFruitImpl"); private final String key; private final String value; CookingEnum(String key, String value) { this.key=key; this.value=value; } /** * 获取key * @return */ public String getKey(){ return key; } /** * 获取value * @return */ public String getValue(){ return value; } }
控制器调用
/** * 模板方法设计模式+策略模式 * 根据食物类型选择不同的工序出餐享用 * @param foodType * @return */ @GetMapping("/cook") public ResponseModel cook(String foodType) { String serviceName=""; if (CookingEnum.FRUIT.getKey().equals(foodType)){ serviceName=CookingEnum.FRUIT.getValue(); }else if (CookingEnum.VEGETABLE.getKey().equals(foodType)){ serviceName=CookingEnum.VEGETABLE.getValue(); }else { log.error("超标了,做不出来这种饭"); return new ResponseModel("超标了,做不出来这种饭", 500, null); } Cookingtemplate bean = applicationContext.getBean(serviceName, Cookingtemplate.class); String make = bean.make(); return new ResponseModel("做好了", 200, make); }
测试案例
2022-06-12 23:41:04.591 INFO 21536 --- [nio-8081-exec-6] c.k.s.d.t.impl.CookingVegetableImpl : 买些菠菜,土豆,西红柿 2022-06-12 23:41:04.591 INFO 21536 --- [nio-8081-exec-6] c.k.s.d.t.impl.CookingVegetableImpl : 把蔬菜洗干净 2022-06-12 23:41:04.591 INFO 21536 --- [nio-8081-exec-6] c.k.s.d.t.impl.CookingVegetableImpl : 做个西红柿炒土豆丝,炒个菠菜 2022-06-12 23:41:04.591 INFO 21536 --- [nio-8081-exec-6] c.k.s.d.t.impl.CookingVegetableImpl : 享用小炒
2022-06-12 23:42:13.353 INFO 21536 --- [nio-8081-exec-9] c.k.s.d.template.impl.CookingFruitImpl : 买些苹果,芒果,香蕉,水蜜桃 2022-06-12 23:42:13.353 INFO 21536 --- [nio-8081-exec-9] c.k.s.d.template.impl.CookingFruitImpl : 把水果洗干净 2022-06-12 23:42:13.353 INFO 21536 --- [nio-8081-exec-9] c.k.s.d.template.impl.CookingFruitImpl : 放点沙拉酱做水果沙拉 2022-06-12 23:42:13.353 INFO 21536 --- [nio-8081-exec-9] c.k.s.d.template.impl.CookingFruitImpl : 享用水果沙拉
原创文章,作者:Carrie001128,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/274299.html