绑定完请刷新页面
取消
刷新

分享好友

×
取消 复制
设计模式之模板方法模式
2022-09-29 18:21:08

在我们实际开发中,如果一个方法极其复杂时,如果我们将所有的逻辑写在一个方法中,那维护起来就很困难,要替换某些步骤时都要重新写,这样代码的扩展性就很差,当遇到这种情况就要考虑今天的主角——模板方法模式。

一、概念理解

模板方法模式的概念很简单,在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中,模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。

既然概念叫“骨架”,那想当然的就是定义一个抽象类,这是模板方法模式的个角色——抽象模板角色,要有延迟子类实现骨架方法,这是模板方法的第二个角色——具体模板角色。

抽象模板角色:定义了一个或多个抽象操作,以便让子类实现。这些抽象操作叫做基本操作,它们是一个逻辑的组成步骤,定义并实现了一个模板方法。

具体模板角色:实现父类所定义的一个或多个抽象方法,它们是一个逻辑的组成步骤。每一个抽象模板角色都可以有任意多个具体模板角色与之对应。

二、案例实现

在我们的业务开发中往往都需要很多对象、很多方法,对象间也大都存在依赖关系,如果我们手动创建、管理对象就是一件极其困难的事。

如果我们使用工厂模式用于创建对象,使用一个容器用于管理对象,那么再使用起来就变得极其简单了。

在“这个过程”中创建对象就是一个很复杂的算法,而且创建对象的方式往往也不是单一的,我们要考虑能替换算法,这时候就可以使用模板方法模式。

假设创建对象有两种方式,一种是基于注解,一种是基于xml,我们就将该方法定义为一个模板方法,基于注解和基于xml让子类去实现。

我们用refresh()方法代表这个复杂的过程,在这个过程中应该包括:

①开始工作前的预处理;

②创建管理对象的容器(模板方法,基于注解和基于XML交给子类实现);

③模板方法(交给子类,方便扩展);

④其他方法(容器刷新后、国际化、应用监听、发布事件,等等等一堆事)。

我们基于模板方法模式我们实现简单的demo。

抽象模板角色:

我们在抽象模板角色中实现部分逻辑,而创建对象的容器obtainFreshBeanFactory()方法交给子类实现,onRefresh()空方法交给子类实现便于扩展。

/**
 * 抽象模板角色
 * @author tcy
 * @Date 28-09-2022
 */
public abstract class AbstractApplicationContext {

    /**
     * 案例中容器和对象的创建全过程
     */
    public void refresh(){

        this.prepareRefresh();

        this.obtainFreshBeanFactory();

        this.onRefresh();
    }

    protected void prepareRefresh(){
        System.out.println("我用于开始工作前的预处理...");
    }

    protected void obtainFreshBeanFactory(){
        System.out.println("我用于创建默认管理对象的容器...");
    }

    /**
     * 模板方法,子类去实现[springboot实现了他,感兴趣具体可以研究一下]
     */
    protected void onRefresh() {
    }


    protected void otherMethod(){
        System.out.println("容器刷新后、国际化、应用监听、发布事件,等等等,一堆事");
    }
}

具体模板角色-基于注解创建管理对象的容器

/**
 * 具体模板角色-基于注解
 * @author tcy
 * @Date 28-09-2022
 */
public class ApplicationContextAnnotation extends AbstractApplicationContext {
    @Override
    protected void obtainFreshBeanFactory() {
        System.out.println("这是基于注解的创建对象容器...");
    }
}

具体模板角色-基于xml创建管理对象的容器

/**
 * 具体模板角色-基于xml
 * @author tcy
 * @Date 28-09-2022
 */
public class ApplicationContextXml extends AbstractApplicationContext {
    @Override
    protected void obtainFreshBeanFactory() {
        System.out.println("这是xml的创建对象容器...");
    }
}

客户端-模拟容器启动过程:

/**
 * 容器启动过程
 * @author tcy
 * @Date 28-09-2022
 */
public class Client {
    public static void main(String[] args) {

		//基于xml方式
        ApplicationContextXml applicationContextXml = new ApplicationContextXml();
        applicationContextXml.refresh();

		//基于注解方式
        ApplicationContextAnnotation annotation=new ApplicationContextAnnotation();
        annotation.refresh();

    }
}
我用于开始工作前的预处理...
这是xml的创建对象容器...
容器刷新后、国际化、应用监听、发布事件,等等等,一堆事
我用于开始工作前的预处理...
这是基于注解的创建对象容器...
容器刷新后、国际化、应用监听、发布事件,等等等,一堆事

对Spring源码稍微有点了解的同学大概已经知道,我们案例实现的正是简易版的Spring的Refresh()方法,Refresh()方法是Spring核心的方法,Spring良好的扩展性正是离不开模板方法模式的运用。下图为Spring核心Refresh()方法的执行大流程注释。

image-20220929094055185

在我们案例中的onRefresh()的空方法,实际中Springboot就是实现了这个空方法,onRefresh()方法调用了Tomcat的jar包启动,这也是Springboot不需要手动注入Tomcat的原因。

相信通过这个案例的理解,大部分同学不仅能很好的理解模板方法模式,想必对Spring的启动过程也有了一个大概的了解。

三、总结

模板方法应用场景太普遍了,在实际开发中有多个子类共有的方法,并且逻辑相同,可以考虑使用模板方法模式。当面对重要、复杂的算法,也可以把核心算法设计为模板方法模式,相关细节则由各个子类实现。

模板方法优点突出:封装不变部分,扩展可变部分;提取公共代码,便于维护;行为由父类控制,子类实现。

模板方法的缺点很明显,当方法实现过多的时候,每一个不同的实现都需要一个子类来实现,这必然导致类的个数增加,使得系统变得更加庞大。

个人独立开发的应用框架芒果管理系统后端,支持前后端代码生成、支持字段注解等实用开发功能已全部开源,感兴趣的同学可以点个star鼓励我一下。这是芒果管理系统前端

分享好友

分享这个小栈给你的朋友们,一起进步吧。

重学 Java 设计模式
创建时间:2020-06-03 14:48:59
技术好就一定能写出好代码吗?不能!再漂亮的马桶放到厨房都略显尴尬!无论是家里装修还是上道开车,只有通过实战才能快速将理论转变为技能。毕竟设计模式也是源于 克里斯托佛·亚历山大 的著作 《建筑模式语言》。
展开
订阅须知

• 所有用户可根据关注领域订阅专区或所有专区

• 付费订阅:虚拟交易,一经交易不退款;若特殊情况,可3日内客服咨询

• 专区发布评论属默认订阅所评论专区(除付费小栈外)

栈主、嘉宾

查看更多
  • 小傅哥
    栈主

小栈成员

查看更多
  • 小雨滴
  • 马延龙
  • wojiuzhuai
  • 水煮陈福
戳我,来吐槽~