Java设计模式系列之——模板方法模式

大事件

关注篮球或者喜欢逛社交网站的朋友们可能都知道,2019年10月5日,NBA休斯顿火箭队总经理莫雷在推特上发布了一张无知的涉港图片,引发全体中国人民的强烈抗议和不满,一时间舆论哗然,此后,NBA总裁肖华回应此时称支持莫雷,再度引爆舆论。事件发展到今天已经过了一周了,主要矛盾制造者、当事人莫雷和笑话无任何道歉悔意,甚至将矛盾转移到两国之间的各种人群中。其态度傲慢、用心险恶,公然干涉他国内政和主权完整,这次我们一定不会善罢甘休。

这些天,推特、微博、虎扑、知乎等各大网站都因为此事件战火弥漫,网民都在有关此事件的新闻下各显神通,使出浑身解数,各种评论段子层出不穷,各种污言秽语不堪入目。在这儿也请同胞们不要被不怀好意的人利用舆论谩骂自己同胞,不要自己内部开始瓦解,我们只要抓住主要矛盾,莫雷必须站出来道歉,必须辞去火箭队总经理职位,肖华也必须站出来道歉,解雇莫雷。这才是道歉最基本的诚意,才有可能挽回一点中国球迷的心。

当然时间最终会给我们一个答案,在等待答案的日子里,全球各地,社会各界会有越来越多的人就此事发声,我们当然也不会闲着,在各大社交媒体软件上每天“问候”莫雷,以表示我们的“言论自由”。

这是湖人球员詹姆斯今天接受媒体采访后,连发两条推特谈论莫雷事件,目前下面评论都是喷他的,可以说里外不是人了。不过这不是本篇的重点,作为技术公众号,我们从技术的角度来思考一下,这件事发生以来,舆论是怎样发酵的?是通过什么样的方式呢?来进入我们今天的主题,Java设计模式之——模板方法模式。

什么是模板方法模式

Define the skeleton of an algorithm in an operation,deferring some steps to subclasses.

Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's  structure.

模板方法模式(Template Method Pattern):定义一个操作中的算法的框架,而将一些步骤延迟到子类中。模板方法允许子类在不改变算法结构的情况下重新定义算法的某些步骤。模板方法模式属于行为型模式,主要使用Java的继承机制来实现。

模板方法,顾名思义就是一个模板,按照模板做事,模板方法里封装了方法的执行步骤,调用方只需要通过调用模板就能按照正确的顺序把事情做好。

模板方法模式的两个角色

  • AbstractClass(抽象类):定义了一系列基本操作(PrimitiveOperations),这些基本操作(方法)可以是具体的,也可以是抽象的,每一个基本操作对应算法的一个步骤,在其子类中可以重定义或实现这些步骤。同时,在抽象类中定义了一个模板方法(Template Method),也就是定义了一个算法的框架,并定义组合好了这些操作的执行顺序。

  • ConcreteClass(具体子类):抽象类的子类,用于实现在父类中声明的抽象基本操作以完成子类特定算法的步骤,也可以覆盖在父类中已经实现的具体基本操作。


 

模板方法模式UML图

模板方法模式代码演示

有小伙伴要问了,模板方法模式和莫雷事件有什么关系吗?他们二者之间本身并没有任何关联,我是在观察大家在面对这件事的态度,以及我们表达我们观点所采用的方式。再抽象一下,我们每个人对这件事的行为是不是可以简单的抽象成,打开社交软件,发表观点和意见、关闭社交软件。这是什么?运用到项目上来看,这不就是一个模板方法吗?大家都是按照这个模板在表达观点,不同的是有的人用的微博,有的人用的虎扑,有的用的推特,有的支持莫雷,有的骂莫雷等等。我们来看一下代码实现。

1、编写抽象模板类

package com.mazhichu.designpatterns.templatemethod;/** * <p class="detail"> * 功能: 抽象模板类 * </p> * * @author Moore * @ClassName Comment. * @Version V1.0. * @date 2019.10.16 11:53:02 */public abstract class Comment {    /**     * <p class="detail">     * 功能: 基本抽象方法     * </p>     *     * @author Moore     * @date 2019.10.16 11:53:02     */    protected abstract void openSocialSoftware();    /**     * <p class="detail">     * 功能: 基本抽象方法     * </p>     *     * @author Moore     * @date 2019.10.16 11:53:02     */    protected abstract void comment();    /**     * <p class="detail">     * 功能: 具体方法     * </p>     *     * @author Moore     * @date 2019.10.16 11:53:02     */    protected void closeSocialSoftware(){        System.out.println("关闭社交软件");    }    /**     * <p class="detail">     * 功能: 模板方法,模板方法,为了防止恶意的操作,一般模板方法都加上final关键字,子类不可实现     * </p>     *     * @author Moore     * @date 2019.10.16 11:53:02     */    public final void temtemplateMethod(){        openSocialSoftware();        comment();        closeSocialSoftware();    }}

2、编写具体类

package com.mazhichu.designpatterns.templatemethod;/** * <p class="detail"> * 功能: 具体类 * </p> * * @author Moore * @ClassName Zhang san. * @Version V1.0. * @date 2019.10.16 14:00:09 */public class ZhangSan extends Comment {    /**     * <p class="detail">     * 功能: 基本抽象方法     * </p>     *     * @author Moore     * @date 2019.10.16 11:53:02     */    @Override    protected void openSocialSoftware() {        System.out.println("打开微博!");    }    /**     * <p class="detail">     * 功能: 基本抽象方法     * </p>     *     * @author Moore     * @date 2019.10.16 11:53:02     */    @Override    protected void comment() {        System.out.println("评论是:莫雷必须道歉,肖华必须道歉!解雇莫雷!");    }}
package com.mazhichu.designpatterns.templatemethod;/** * <p class="detail"> * 功能: 具体类 * </p> * * @author Moore * @ClassName Li si. * @Version V1.0. * @date 2019.10.16 13:59:56 */public class LiSi extends Comment {    /**     * <p class="detail">     * 功能: 基本抽象方法     * </p>     *     * @author Moore     * @date 2019.10.16 11:53:02     */    @Override    protected void openSocialSoftware() {        System.out.println("打开虎扑");    }    /**     * <p class="detail">     * 功能: 基本抽象方法     * </p>     *     * @author Moore     * @date 2019.10.16 11:53:02     */    @Override    protected void comment() {        System.out.println("评论是:莫雷是傻X,WQNMLGB");    }}
package com.mazhichu.designpatterns.templatemethod;/** * <p class="detail"> * 功能: 具体类 * </p> * * @author Moore * @ClassName James. * @Version V1.0. * @date 2019.10.16 13:59:01 */public class James extends Comment {    /**     * <p class="detail">     * 功能: 基本抽象方法     * </p>     *     * @author Moore     * @date 2019.10.16 11:53:02     */    @Override    protected void openSocialSoftware() {        System.out.println("打开推特");    }    /**     * <p class="detail">     * 功能: 基本抽象方法     * </p>     *     * @author Moore     * @date 2019.10.16 11:53:02     */    @Override    protected void comment() {        System.out.println("评论是:肖华应该惩罚莫雷!");    }}

3、客户端调用

package com.mazhichu.designpatterns.templatemethod;public class Client {    public static void main(String[] args) {        Comment zhangSan = new ZhangSan();        zhangSan.temtemplateMethod();        System.out.println("-----------------\n");        Comment lisi = new LiSi();        lisi.temtemplateMethod();        System.out.println("-----------------\n");        Comment james = new James();        james.temtemplateMethod();    }}

查看运行结果:

上面就是模板方法模式,可能是最常见也是最简单的设计模式了,父类(抽象类)定义算法和模板方法,模板方法约定好算法执行顺序,子类只需要实现父类的抽象算法,就能按照模板方法既定的顺序执行得到不同的结果,这样做大大简化了子类的复杂度。

钩子方法

为什么把这个单独拿出来说,是因为在模板方法中有些方法是否执行是可选的,也就是不是所有模板中的算法都需要被执行,可以由子类来决定,这就是我们要说的“钩子方法”。

钩子方法是一种被声明在抽象类中的方法,一般是空实现或者有默认值,子类可以实现覆盖该钩子,来决定算法步骤的某一步骤是否要执行,这是一种反向控制。

我们来改造一下抽象类,加入钩子方法。

1、重新抽象类,加入钩子方法

package com.mazhichu.designpatterns.templatemethod;/** * <p class="detail"> * 功能: 抽象模板类 * </p> * * @author Moore * @ClassName Comment. * @Version V1.0. * @date 2019.10.16 11:53:02 */public abstract class Comment {    /**     * <p class="detail">     * 功能: 基本抽象方法     * </p>     *     * @author Moore     * @date 2019.10.16 11:53:02     */    protected abstract void openSocialSoftware();    /**     * <p class="detail">     * 功能: 基本抽象方法     * </p>     *     * @author Moore     * @date 2019.10.16 11:53:02     */    protected abstract void comment();    /**     * <p class="detail">     * 功能: 具体方法     * </p>     *     * @author Moore     * @date 2019.10.16 11:53:02     */    protected void closeSocialSoftware(){        System.out.println("关闭社交软件");    }    /**     * <p class="detail">     * 功能: 模板方法,为了防止恶意的操作,一般模板方法都加上final关键字,子类不可实现     * </p>     *     * @author Moore     * @date 2019.10.16 11:53:02     */    public final void temtemplateMethod(){        openSocialSoftware();        if(isLogin()){            comment();        }else {            System.out.println("您未登录,不可以发表评论哦,只能看别人骂莫雷");        }        closeSocialSoftware();    }    /**     * 钩子方法:可以是抽象方法,空实现或默认实现,子类可以覆写来决定模板方法是否执行某些算法     * @return     */    protected boolean isLogin(){        System.out.println("登录后才可以评论---");        return true;    }}

2、编写一个覆盖钩子方法的子类

package com.mazhichu.designpatterns.templatemethod;public class LaoBao extends Comment {    /**     * <p class="detail">     * 功能: 基本抽象方法     * </p>     *     * @author Moore     * @date 2019.10.16 11:53:02     */    @Override    protected void openSocialSoftware() {        System.out.println("打开知乎");    }    /**     * <p class="detail">     * 功能: 基本抽象方法     * </p>     *     * @author Moore     * @date 2019.10.16 11:53:02     */    @Override    protected void comment() {        System.out.println("我不但想骂莫雷肖华,还想问候川普");    }    @Override    protected boolean isLogin() {        return false;    }}

3、客户端调用

package com.mazhichu.designpatterns.templatemethod;public class Client {    public static void main(String[] args) {        Comment zhangSan = new ZhangSan();        zhangSan.temtemplateMethod();        System.out.println("-----------------\n");        Comment lisi = new LiSi();        lisi.temtemplateMethod();        System.out.println("-----------------\n");        Comment james = new James();        james.temtemplateMethod();        System.out.println("-----------------\n");        Comment laobao = new LaoBao();        laobao.temtemplateMethod();    }}

4、查看运行结果:

通过结果可以得出,加入钩子方法后,可以反向控制父类中的模板方法中某些算法是否要被执行,这样也增加了模板方法的灵活性。

总结

模板方法模式优点

  • 良好的封装性和扩展性。把公共行为封装在父类,通过子类实现具体行为逻辑,增加功能由子类实现基本方法扩展,复合单一职责原则和开闭原则。

  • 提高代码的复用性,模板方法模式就是一种代码复用技术,在类库设计中尤为重要。

  • 反向控制,通过子类覆盖父类的钩子方法来决定某一特定步骤是否需要执行。

模板方法模式缺点

  • 模板方法使用继承方式复用代码,如果要在抽象类里增加一个抽象方法,则每一个子类都要修改代码。

  • 每一个不同的实现都需要通过一个子类来实现,导致类的个数增加,系统变得庞大。

模板方法应用场景

  • 多个子类中有公共的方法,并且逻辑相同,可以集中到公共父类中防止代码重复。

  • 一些重要复杂的算法,可以把算法中不变的部分设计成模板方法,可变的部分由子类实现。

  • 需要通过子类来控制父类中某个算法是否执行,通过钩子方法实现反向控制。

知识点,用笔记下来

  • 为防止恶意操作,一般都在模板方法上加上 final 关键词,防止子类改变模板方法中的算法执行顺序。

  • 策略模式和模板方法都是用于封装算法,前者是利用组合和委托模型,而后者则是继承。

番外

上面就是关于模板方法模式的讲解,其实很简单,就是我们常用的封装和继承。这儿想说的是,其实设计模式没有那么枯燥与复杂,平常多留意我们生活中的日常琐事,多思考,知识都来源于生活的观察与总结,设计模式也在我们生活中的点点滴滴里。最后,香港是中国的,任何国家、任何组织、任何势力、任何个人都无权干预我国内政,无权干涉我们领土主权的完整。希望香港早日安宁下来,再谈其他事。

我不能保证我写的文章都是正确的,但是我能保证都是我自己花时间用心写的,所有的代码示例都是原创,所有的理解都只是我个人理解,不能代表官方权威,所以请各位读者阅读时带着批判的眼光,有选择性的认同,谢谢!

文章同步公众号:码之初,每天推送Java技术文章,期待您的关注!还可以加我的个人微信qingtian-1989,备注技术群,一起在群里讨论技术和生活。

原创不易,转载请注明出处,谢谢!

发布了23 篇原创文章 · 获赞 12 · 访问量 5766

猜你喜欢

转载自blog.csdn.net/u013469325/article/details/105246686