设计模式-模板方法模式(二)

概述

  模板方法(Template method)模式,定义了一个算法的步骤,并允许子类为算法中的某些步骤提供实现。也就是说,模板方法模式可以使得子类在不改变算法结构的情况下,自定义算法的实现。

  也就是说,当我们要做某一件事的时候,这件事情的步骤是固定的,但每个步骤的具体实现方式是不一定的,模板方法模式就是针对这种场景出现的。拿日常生活中的情况举例,比如我们每天的工作:上班打卡 -> 工作 -> 下班打卡,一般情况下,我们每个人都需要打卡,但我们工作的内容是不同的;比如我们出去吃饭:点餐 -> 吃饭 -> 付款,点餐和付款我们都一样,但吃什么饭就不同了;还有常用的去银行办理业务:取号 -> 办理业务 -> 结束,取号和结束都一样,但办理业务可能是取款,转账,办卡等。这样的场景我们可以举出好多,所谓设计模式源于生活,正所谓如此吧。

模式结构

结构图

  模板方法模式是一种结构很简单的行为型设计模式,在其结构中只存在父类与子类之间的继承关系。通过使用模板方法模式,可以将一些复杂流程的实现步骤封装在一系列基本方法中,在抽象父类中提供一个称之为模板方法的方法来定义这些基本方法的执行次序,而通过其子类来覆盖某些步骤,从而使得相同的算法框架可以有不同的执行结果。首先,我们来简单看下它的UML结构图:

模板方法模式结构图.png

这里对UML图简单说一些,+代表public方法,#代表protected方法,-代表private方法。

角色

由于模板方法模式是基于继承实现的,所以该模式大致分为两种角色:抽象模板(AbstractTemplate),具体模板(ConcreteTemplate)。

  1. 抽象模板:

a. 抽象模板类定义了一系列基本操作(PrimitiveOperations),这些操作可以是抽象的,也可以是具体的,每一个操作对应算法的一个实现步骤,而在子类中可以重写或实现这些步骤。

b. 抽象类中实现了一个或多个模板方法,用于定义一个算法的完整步骤。该方法通常情况下会定义为final类型,防止子类对算法的步骤进行修改。而在该方法内部,会调用我们的抽象方法或具体方法来一步一步实现整个算法。

  1. 具体模板

具体模板一般要实现父类所定义的一个或多个抽象方法,来完成我们所需要的功能。通过不同的具体模板类实现父类的抽象方法,从而完成不同功能的实现。

方法

而对应的方法又可以分为以下几种:

  • abstractMethod:抽象方法由抽象类声明,然后由子类实现。
  • concreteMethod:具体方法,由抽象类声明并实现,一般情况下子类并不去重写覆盖。
  • hookMethod:钩子方法,由抽象类声明并实现,然后子类一般会重写覆盖。通常清空下,抽象类提供的是一个默认实现。
  • templateMethod:模板方法是通过其他方法进行组合的一种方法,由抽象类声明并实现,通常情况下定义为final类型。
钩子方法

  这里的钩子方法和我们平时理解的钩子方法是不同的,平时的钩子可能会用于系统监听,鼠标监听之类的功能,这里的钩子方法是为了将父类的功能延迟到子类实现,并且这里的钩子方法和抽象方法还是有点相似的。

  1. 由于模板方法是由抽象方法和具体方法来组合起来的,这时候如果我们想改变方法的步骤,比如如果某个条件是true的时候,就执行A方法,否则执行B方法。也就是说,通过钩子可以让我们在实现模板方法的时候,决定哪些步骤是可选的,实现方式则是通过在子类中实现钩子方法来完成这种操作。
  2. 钩子方法和抽象方法不同的是,抽象类中钩子方法会有一个默认的实现。
  3. 另外一点,钩子方法应该是我们一开始设计抽象类的实现就确定的,而不是以后添加的。

实例模型

我们使用简单的代码示例来加深一下我们对模板方法模式的理解:

package com.template;

/**
 * 模板方法相关
 *
 * @author zhangkeke
 * @since 2018/3/5 15:46
 */
public abstract class AbstractTemplate {

    /**
     * 模板方法
     */
    public final void templateMethod() {
        //调用基本方法
        abstractMethod();
        hookMethod();
        concreteMethod();
        if (isSuccess()) {
            concreteMethod2();
        }
    }

    /**
     * 抽象方法,又子类实现其功能
     */
    protected abstract void abstractMethod();

    /**
     * 钩子方法,提供默认实现
     */
    protected void hookMethod(){
        System.out.println("default implement");
    }

    /**
     * 钩子方法测试
     * @return
     */
    protected boolean isSuccess() {
        return true;
    }
    

    /**
     * 具体方法,一般情况下在抽象类中声明并实现,并且一般私有
     */
    private final void concreteMethod(){
        System.out.println("业务相关处理");
    }

    private final void concreteMethod2(){
        System.out.println("测试钩子");
    }
}

钩子方法通常有两种形式:

  1. 一种和抽象方法很像,方法体为空或提供简单实现,由子类来实现,这类方法优于抽象方法的地方就是如果子类没有覆盖,不会编译不通过,而抽象方法则会编译不通过;
  2. 另一种则是让我们在实现抽象类的实现可选的操作,通常方法名为isXXX()的形式类型;

不过一般情况下,Java中对钩子方法的命名通常是doXXX()形式的,在编写相关程序时,我们尽量按照通用的命名方式来命名。

使用场景

  模板方法清晰地划定了某一类业务的变与不变,为一类业务做好了流程框架,为子类提供了公共的代码,并且子类的行为完全由父类来控制,实现了代码的可维护性和可扩展性。父类不容修改,子类可以去扩展,很好地符合了设计模式的开闭原则——对修改封闭,对扩展开放。

  所以我们如果在考虑使用模板方法的情况下,首先要理清楚该算法可变的地方和不可变的地方,然后还要保证算法的实现步骤是固定的(比如我们前面提到的银行办理业务的流程一般就是固定的)。搞清楚之后,我们就可以使用模板方法实现算法的不可变的部分,然后在子类中实现可变的部分。其实在Web开发中,我们经常与模板方法打交道,比如学习servlet过程中的HttpServlet类,最近在学习的Mybatis中的BaseExecutor体系结构等等。

总结

  1. 模板方法模式是一种比较简单的通过继承来实现的行为型模式;
  2. 在模板方法模式中,可以围绕变与不变进行设计抽象模板类,相同的放在抽象类中,不同的放在实现类中;
  3. 为了防止修改模板方法,通常模板类中的模板方法定义为final类型;
  4. 策略模式和模板方法模式有时候会拿来一起比较,因为两者很相似,有时候可以相互替代。它们都是用于封装算法,不过策略模式一般是基于组合和委托的形式,而模板方法模式是基于继承结构的。

本文参考自:
《Java与模式》
设计模式——模板方法设计模式
Java设计模式之模板方法模式

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容