场景:针对不同的度量模型来执行不同的方法,支持后面用最少的代码、最简单的方法来复用实现更多度量模型。
概念
在一个方法中定义了一个算法的骨架或者步骤,而将一些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法接口的情况下,重新定义算法中的某一些步骤。
举例
去银行处理业务步骤:1.取号、2.办业务、3.评价。三个步骤取号和评价都是固定的流程,但是每个人办理业务的不同需要不同的实现,我们就将办业务封装为一个抽象类:
/**
* @Author CMLX
* @Desc -> 模板方法设计模式的抽象类
**/
public abstract class AbstractBusinessHandler {
/**
* 模板方法
*/
public final void execute() {
getNumber();
handler();
judge();
}
/**
* 取号
*/
private void getNumber() {
Random random = new Random();
System.out.println("rowNumber:" + random.nextInt());
}
/**
* 办理
*/
// 抽象的办理业务方法,由子类实现
public abstract void handler();
/**
* 评价
*/
private void judge() {
System.out.println("give a judge");
}
}
现在有人想办理业务就只需要继承这个抽象类重写handle方法,然后使用实现类对象调用execute方法就可以完成整个办理业务的流程。
/**
* @Author CMLX
* @Desc -> 存钱实现类
**/
public class SaveMoneyHandler extends AbstractBusinessHandler{
@Override
public void handler() {
System.out.println("save money $100");
}
public static void main(String[] args) {
SaveMoneyHandler saveMoneyHandler = new SaveMoneyHandler();
saveMoneyHandler.execute();
}
}
模板方法模式是结构最简单的行为型设计模式,在其结构中只存在父类与子类之间的继承关系。通过使用模板方法模式,可以将一些复杂流程的实现步骤封装在一系列基本方法中,在抽象父类中提供一个称之为模板方法的方法来定义这些基本方法的执行次序,而通过其子类来覆盖某些步骤,从而使得相同的算法框架可以有不同的执行结果。模板方法模式提供了一个模板方法来定义算法框架,而某些具体步骤的实现可以在其子类中完成。
钩子方法
当模板方法中某一些步骤是可选的时候,也就是该步骤不一定执行,可以由子类来决定是否执行,这个时候就需要用上钩子。钩子是一种被声明在抽象类中的方法,但一般来说它只是空的或者具有默认值,子类可以实现覆盖该钩子,来设置算法步骤的某一步骤是否要执行。钩子可以让子类实现算法中可选的部分,让子类能够有机会对模板方法中某些一即将发生的步骤做出反应。
用银行办理业务的例子,买东西可以不用取号,那么代码实现如下:
/**
* @Author CMLX
* @Desc -> 模板方法设计模式的抽象类
**/
public abstract class AbstractBusinessHandler {
/**
* 模板方法
*/
public final void execute() {
if (handler() == 1) {
getNumber();
}
handler();
judge();
}
/**
* 是否是VIP
* 通过处理业务不同来哦安定
*/
public abstract int handler();
/**
* 取号
*/
private void getNumber() {
Random random = new Random();
System.out.println("rowNumber:" + random.nextInt());
}
/**
* 办理
*/
// 抽象的办理业务方法,由子类实现
public abstract void handler();
/**
* 评价
*/
private void judge() {
System.out.println("give a judge");
}
}
实现类
/**
* @Author CMLX
* @Desc -> 存钱实现类
**/
public class SaveMoneyHandler extends AbstractBusinessHandler{
@Override
public int handler() {
return 1;
}
@Override
public void handler() {
System.out.println("save money $100");
}
public static void main(String[] args) {
SaveMoneyHandler saveMoneyHandler = new SaveMoneyHandler();
saveMoneyHandler.execute();
}
}
/**
* @Author CMLX
* @Desc -> 购物实现类
**/
public class ShoppingHandler extends AbstractBusinessHandler{
@Override
public int handler() {
return 0;
}
@Override
public void handler() {
System.out.println("Shopping");
}
public static void main(String[] args) {
ShoppingHandler shoppingHandler = new ShoppingHandler();
shoppingHandler.execute();
}
}
整合Spring
上面只是说明了整个实现原理,但是在开发过程中需要融入到Spring,根据入参不同怎么获取到不同实现类对象的实例,如下
/**
* @Author CMLX
* @Desc -> 将AbstractBusinessHandler实现类全部注入到Spring容器中
**/
@Configuration
public class businessHandleConfig {
// 实现类需要用@Component注入
@Autowired
List<AbstractBusinessHandler> businessHandlers;
@Bean
HashMap<Integer, AbstractBusinessHandler> businessHandleScript() {
HashMap<Integer,AbstractBusinessHandler> map = new HashMap<>();
for (AbstractBusinessHandler businessHandler : businessHandlers) {
map.put(businessHandler.isVip(),businessHandler);
}
return map;
}
}
/**
* @Author CMLX
* @Date -> 2021/5/12 12:20
* @Desc -> 测试Controller
**/
@RestController
public class TestBusinessHandleController {
@Autowired
HashMap<Integer,AbstractBusinessHandler> scrips;
@RequestMapping("/test")
public ModelAndView test(Integer type){
// 根据入参不同,通过type获取对应的实现类,完成相应的逻辑
AbstractBusinessHandler abstractBusinessHandler = scrips.get(type);
abstractBusinessHandler.execute();
return null;
}
}