前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >设计模式——模板模式

设计模式——模板模式

作者头像
Java架构师必看
发布2021-05-14 11:17:21
3100
发布2021-05-14 11:17:21
举报
文章被收录于专栏:Java架构师必看

设计模式——模板模式

强烈推介IDEA2020.2破解激活,IntelliJ IDEA 注册码,2020.2 IDEA 激活码

在面向对象程序设计过程中,程序员常常会遇到如下情况:设计一个系统时知道算法所需的关键步骤,且确定了这些步骤的执行顺序,但某些步骤的具体实现还未知,或者说某些步骤的实现与具体的环境相关。例如:去医院看病一般都要经历以下流程:挂号、排队、就诊、取药等,其中挂号和排队对每个客户都是一样的,可以在父类中实现,但是就诊和取药是因人而异的。可以延迟到子类中实现。我们把这些规定了流程或格式的实例定义成模板,允许使用者根据自己的需求去更新它。

一、模板模式的基本介绍


1)、模板方法模式(Template Method Pattern),又叫模板模式(Template Pattern),在一个抽象类公开定义了执行此方法的模板。它的子类可以按照需要重写方法实现,但调用将以抽象类中定义的方式进行。 2)、简单说,模板方法模式定义了一个操作中的算法骨架,而将步骤延迟到子类中,使得子类可以不改变一个算法的结构,就可以重定义该算法的某些特定步骤。 3)、这种类型的设计模式属于行为型模式。

二、模板方式的特点


模板方式的优点:【1】封装了不变的部分,扩展可变部分。将不变部分的算法封装到父类中实现,而把可变部分的算法由各子类实现。便于子类继续扩展。 【2】在父类中提取了公共的部分代码,便于代码复用。 【3】部分方法是由子类实现的,因此子类可以通过扩展方式增加相应的功能,符合开闭原则。 模板方式的缺点:【1】对每个不同的实现都需要定义一个子类,这个导致类的个数增加,系统更加庞大,设计也更加抽象。 【2】父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结构,提高了代码的阅读难度。 使用场景:【1当多个子类具有公用的方法,却执行流程逻辑相同时。 【2】重要的、复杂的方法,可以考虑作为模板方法。 注意事项:为了防止恶意操作,一般模板方法上都加有 final 关键字

三、模板方法模式结构类图


模板方法模式包含以下主要角色:【1】抽象类(Abstract Class):负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成,如下:     ① 抽象方法:在抽象类中申明,由具体子类实现。     ② 具体方法:在抽象类中已经实现,再具体子类中可以继承或重写它。     ③ 钩子方法:在抽象类中已经实现,例如:用于判断的逻辑方法或者定义一个空方法。子类根据情况要不要重写此方法,此方法为钩子方法。例如下面实例中的 isRecipe() 方法。 【2】具体子类(Concrete Class):实现抽象类中所定义的抽象方法和钩子方法,它们是一个顶级逻辑的一个组成步骤。

四、 模板方式模式案例分析


【1】抽象类(医院看病时,整个流程的抽象类)真个流程属于不可变的,因此我使用了 final 修饰。

代码语言:javascript
复制
public abstract class AbstractHospital {
    //流程
    public final void procedure() {
        //1、挂号
        this.regiest();
        //2、排队
        this.queue();
        //3、看病
        this.treat();
        //4、取药,有点人不用开药,只是小事
        if(isRecipe()) {
            this.recipe();
        }
    }
    //挂号
    public String regiest() {
        String regiest = "你的订单号为"+((int) (Math.random()*10));
        System.out.println(regiest);
        return regiest;
    }
    //排队
    public void queue() {
        System.out.println("排队中。。。。");
    }
    //看病
    public abstract String  treat();
    //取药
    public abstract String recipe();

    //钩子方法
    boolean isRecipe() {
        return true;
    }
}

【2】抽象类的具体实现类(有多个,我们只写一个)

代码语言:javascript
复制
public class Patient_A extends AbstractHospital{
    @Override
    public String treat() {
        String treat = "胃病";
        System.out.println("你的病为"+treat);
        return treat;
    }
    @Override
    public String recipe() {
        String recipe = "健胃消食片";
        System.out.println("药单:"+recipe);
        return recipe;
    }

    //重写钩子方法
    @Override
    boolean isRecipe() {
        return false;
    }
}

【3】客户端类:创建子类对象,流程调用的是父类公共的流程方法。

代码语言:javascript
复制
public class Client {
    public static void main(String[] args) {
        //A 病人看病
        Patient_A patient_A = new Patient_A();
        //看病的流程
        patient_A.procedure();
        /**
         * 输出如下:
         * 你的订单号为2
         * 排队中。。。。
         * 你的病为胃病
         * 药单:健胃消食片 ==== 加了钩子程序则不显示
         */
        //B 病人看病,的流程也是一样,只需要实例化B,并调用公共的模板流程即可,提高代码的利用率
    }
}

五、模仿方法模式应用源码分析


模板方法模式在 Spring 框架应用的源码分析:Spring IOC 容器初始化时运用到了模板方法模式;

【1】抽象类:AbstractApplicationContext 继承接口(ConfigurableApplicationContext)其中的 refresh 方法就是模板方法,定义了执行的流程,方法中包含钩子方法、子类需要实现的抽象方法(refreshBeanFactory)、父类已实现的方法等等。

代码语言:javascript
复制
public abstract class AbstractApplicationContext extends DefaultResourceLoader
        implements ConfigurableApplicationContext, DisposableBean {
    ......
    @Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            prepareRefresh();

            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            prepareBeanFactory(beanFactory);

            try {
                // 钩子方法,子类自行选择是否重写
                postProcessBeanFactory(beanFactory);

                invokeBeanFactoryPostProcessors(beanFactory);

                registerBeanPostProcessors(beanFactory);

                // 父类已实现
                initMessageSource();

                // 由父类进行实现
                initApplicationEventMulticaster();

                // 钩子方法
                onRefresh();

                registerListeners();

                finishBeanFactoryInitialization(beanFactory);

                // 父类实现
                finishRefresh();
            }

            catch (BeansException ex) {

                destroyBeans();

                cancelRefresh(ex);

                throw ex;
            }
        }
    }
    ......
}

【2】构建 AbstractApplicationContext  类图:

六、模板方法模式的注意事项和细节


【1】基本思想是:算法只存在于一个地方,也就是父类中,容易修改。需要修改算法时,只要修改父类的模板方法或者已经实现的某些步骤,子类就会继承这些修改。 【2】实现了最大化代码复用。父类的模板方法和已实现的某些步骤会被子类继承且直接使用。 【3】既统一了算法,也提供了很大的灵活性。父类的模板方法确保了算法的结构不变,同时由子类提供部分步骤的实现。 【4】该模式的不足之处:每一个不同的实现都需要一个子类实现,导致类的个数增多,使得系统更加庞大。 【5】模板方式的使用场景:存在执行一系列步骤,且一类产品的此步骤基本相同,但其中个别步骤的实现细节不同时,通常可以考虑使用模板方法模式。

所属专题
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、模板模式的基本介绍
  • 二、模板方式的特点
  • 三、模板方法模式结构类图
  • 四、 模板方式模式案例分析
  • 五、模仿方法模式应用源码分析
  • 六、模板方法模式的注意事项和细节
    • 所属专题
    相关产品与服务
    容器服务
    腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档