6

设计模式之模板方法模式 - 程序员田同学

 1 year ago
source link: https://www.cnblogs.com/tianClassmate/p/16740392.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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

一、概念理解

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

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

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

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

二、案例实现

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

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

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

假设创建对象有两种方式,一种是基于注解,一种是基于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鼓励我一下。这是芒果管理系统前端

设计模式的学习要成体系,推荐你看我往期发布的设计模式文章。

一、设计模式概述

二、设计模式之工厂方法和抽象工厂

三、设计模式之单例和原型

四、设计模式之建造者模式

五、设计模式之代理模式

六、设计模式之适配器模式

七、设计模式之桥接模式

八、设计模式之组合模式

九、设计模式之装饰器模式

十、设计模式之外观模式

十一、外观模式之享元模式

十二、设计模式之责任链模式

十三、设计模式之命令模式

十四、设计模式之解释器模式

十五、设计模式之迭代器模式

十六、设计模式之中介者模式

十七、设计模式之备忘录模式

十八、设计模式之观察者模式

十九、设计模式之状态模式

二十、设计模式之策略模式


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK