【设计模式】-07模板方法模式

1.什么是模板方法模式?

模板方法模式抽象出一个模板,该模板中具有完成某项功能的算法骨架,模板中只对一些固定不变的算法做实现,其余的算法实现延迟到子类中去实现.

举个生活中的例子,比如去银行办业务,一般需要以下几个步骤:

①取号;②填写办理项目单据;③等待叫号;④窗口办理业务. 

其中①,③,④这三个步骤是固定不变的,基本上99%的人去银行办业务都会经历这三个步骤,而且顺序不变,只有步骤②是可变的,每个人所填的单据都是不一样的,所以这一项内容交给客户去做了,其它三项由银行完成,这样一来既方便了客户,也节省了时间,提高了效率.在开发中亦是如此,可以把实现某个功能的固定步骤抽取出来作为一个模板,然后把模板中固定不变的方法在模板中实现(父类),把一些需要变动的方法在模板中抽象,交给继承它的子类去实现,这种设计模式就称之为模板方法模式.

2.为什么要用模板方法模式?

①可以更好的封装代码,体现java语言面向对象的特性.

②提高代码的复用性,将重复不变的部分抽出去让父类实现,子类继承就能直接用,给猿类节省陪女朋友的时间…

③屏蔽细节,子类只需要重点部分差异代码的实现,无需再关心父类中已经实现的代码细节,毕竟专注才能更高效嘛.

④易于维护,较高的复用性使得业务代码重复更少,代码量减少很多,使得代码维护起来更加容易.

3.适用场景

业务中有些功能的实现步骤是比较清晰和固定的,算法或操作中遵循的逻辑相似.

4.实现

我想用代码来实现下”正常”人的一天,总结一下,人的一天不就是起床,吃饭,睡觉,干一些事吗,说简单一点,就像小沈阳当年说的,眼睛一闭一睁,一天没了…观察了很多人的一天,我得出一个模板:

起床,吃饭,做一些事,睡觉. 

其中起床,吃饭,睡觉是不变的,可以在父类中实现,做一些事的话每个人都不一样,不同的人可能会把时间拿来打游戏,工作,学习,娱乐…所以这个步骤我延迟到子类中去实现,由于人太多了,我代码里就尽量简单,举个A人和B人的例子就行了,重在理解…

先创建模板,为了防止子类修改父类中固定不变的方法,父类中固定不变的方法需要加final关键字,同时需要加上private关键字对子类隐藏方法.

/**
 * 模板方法模式-模板:一个人的一天
 */
public abstract class LifeTemplate {
    public void Life() {
        //起床
       getUp();
        //吃饭
        eat();
        //做一些事
        dowork();
        //睡觉
        sleep();
    }

    private final void getUp() {
        System.out.println("起床了...");
    }

    private final void eat() {
        System.out.println("大猪蹄子真好吃...");
    }

    protected abstract void dowork();

    private final void sleep() {
        System.out.println("我要睡个香香觉...");
    }
}

再分别创建A人和B人,继承模板方法并实现抽象方法:

public class PersonA extends LifeTemplate {
    @Override
    protected void dowork() {
        System.out.println("我是A,我在努力工作赚老婆本...");
    }
}


public class PersonB extends LifeTemplate{
    @Override
    protected void dowork() {
        System.out.println("我是B,我很牛逼,不用工作,我在打游戏...");
    }
}

测试一下:

/**
 * 测试类
 */
public class LifeTemplateTest {
    public static void main(String[] args) {
        LifeTemplate A = new PersonA();
        LifeTemplate B = new PersonB();
        System.out.println("有请A表演他的一天>>>");
        A.Life();
        System.out.println("*****************************");
        System.out.println("有请B表演他的一天>>>");
        B.Life();
    }
}

结果如图:

《【设计模式】-07模板方法模式》

嗯,没毛病,模板方法就是好,但是有一天,A经历了双11之后,像我一样不仅吃不起大猪蹄子,连土都吃不起了,怎么办?绝食一天吧…

这个时候由于模板中已经提供了该方法的实现,而且加了fInal,A无可奈何了吧… 这时就需要引出接下来要讲的钩子Hook

可以在模板方法中加上钩子,让子类决定是否调用模板中提供的方法,这样就非常灵活了,你也可以把钩子当做是父类中对应方法的开关,由子类选择开启或关闭.

于是我们可以给模板方法中加上一条if语句和一个方法,默认返回true,也就是默认要吃早饭,该方法不加final,子类可以选择覆盖/不覆盖,修改后的模板方法代码如下:

/**
 * 模板方法模式-模板:一个人的一天
 */
public abstract class LifeTemplate {
    public void Life() {
        //起床
        getUp();
        //吃饭
        if (isEat()) {
            eat();
        }
        //做一些事
        dowork();
        //睡觉
        sleep();
    }

    /**
     * 钩子
     */
    protected boolean isEat() {
        return true;
    }

    private final void getUp() {
        System.out.println("起床了...");
    }

    private final void eat() {
        System.out.println("大猪蹄子真好吃...");
    }

    protected abstract void dowork();

    private final void sleep() {
        System.out.println("我要睡个香香觉...");
    }
}

然后A类中覆盖该钩子,返回false:

public class PersonA extends LifeTemplate {
    @Override
    protected void dowork() {
        System.out.println("我是A,我在努力工作赚老婆本...");
    }

    @Override
    protected boolean isEat() {
        return false;
    }
}

B类不需要变动,因为B是富二代,不需要吃土…

再来测试一下:

《【设计模式】-07模板方法模式》

有了钩子之后,是不是很方便呢?如果哪天B想打游戏打通宵也没问题,加个钩子就行了,哪天再来个C,D,E…分别写个dowork的实现就行了,其他代码直接复用,写代码变得如此简单,终于有时间陪家人了,这就是设计模式的魅力,也难怪大公司都会要求应聘者掌握一些设计模式,确实可以让代码质量提高很多…

5.缺点

凡事有利就有弊,设计模式也是如此,由于java是单继承的,如果你采取了模板方法模式,子类就无法再继承其它的类了,所以在使用过程中需要注意这一点,但无论如何也无法掩盖它的优点,在实际开发中还是很推荐使用的,而且该设计模式在三大运营商的日志模块的业务代码里有大量运用,经得起实际考验,所以放心去用吧.

 

    原文作者:设计模式
    原文地址: https://blog.csdn.net/lovexiaotaozi/article/details/84136441
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞