Java设计模式-模板方法模式详解

Java设计模式-模板方法模式

0.前言

模板方法模式(TemplateMethod Pattern):父类(抽象类)中定义处理流程的框架,在子类中实现具体处理。

1.模板方法原理

父类(抽象类)中只定义一些子类需要的抽象方法这些方法的调用步骤(在一个具体的方法中)。

子类实现了父类的抽象方法的具体处理过程。

也就是说,不同的子类虽然具体实现可以各不相同,但是有着一样的处理流程。

若还是觉得抽象的话,看下面这个具体的例子就知道了:

小明和小红都是程序员,每天都会:起床,吃饭,写代码,睡觉。

这相当于父类中的四个抽象方法,父类规定了这些方法的调用顺序为:起床,吃饭,写代码,睡觉。

但是呢:

小明(相当于程序员父类的子类)的具体实现为:8点起床,吃饭吃的外卖,写后端代码,11点睡觉。

小红(相当于程序员父类的子类)的具体实现为:7点起床,吃饭吃自己做的饭菜,写前端代码,10点睡觉。

虽然具体实现不一样,但是四个方法的处理流程是一样的。

注意:这个流程中也可以有具体处理过程一摸一样的方法,需在父类中以具体的方法体现。

比如:小明和小红每天都锻炼半小时,这样原本的程序员父类就有四个抽象方法:起床,吃饭,写代码,睡觉。两个具体的方法:锻炼半小时,处理过程(定义了方法调用顺序)。在处理过程这个具体的方法中,调用顺序为:起床,吃饭,写代码,锻炼半小时,睡觉。

后面的代码也会按照这个例子实现。

2.模板方法模式中的角色

抽象父类AbstractClass:负责定义所需使用的模板方法,可以是抽象方法,也可以有具体的方法。还需有一个具体方法来确定这些方法的调用顺序和一些其他的操作。

具体子类ConcreteClass:负责具体实现抽象父类的抽象方法。无需担心方法的调用和具体处理流程。

3.模板方法模式的UML类图

非常简单,就两个类:

模板方法模式的UML类图

4.代码实现

接下来,用代码模拟上述例子:

程序员父类(抽象父类)

/**
 * 模板方法模式
 * 程序员父类(抽象父类)
 * 4个抽象方法:起床,吃饭,写代码,睡觉
 * 2个具体的方法:锻炼半小时,处理过程
 */
public abstract class Coder {
    public abstract void getup();//起床
    public abstract void eat();//吃饭
    public abstract void code();//写代码
    public abstract void sleep();//睡觉
    public void exercise(){
        System.out.println("锻炼半小时");
    }
    //模板(定义了各个方法的调用顺序和一些其他操作)
    public void TemplateMethod(){
        getup();
        eat();
        code();
        exercise();
        sleep();
    }
}

小明(具体实现类):

public class Ming extends Coder {
    
    @Override
    public void getup() {
        System.out.println("8点起床");
    }

    @Override
    public void eat() {
        System.out.println("吃饭吃的外卖");
    }

    @Override
    public void code() {
        System.out.println("写后端代码");
    }

    @Override
    public void sleep() {
        System.out.println("11点睡觉");
    }
}

小红(具体实现类)

public class Red extends Coder{
    @Override
    public void getup() {
        System.out.println("7点起床");
    }

    @Override
    public void eat() {
        System.out.println("吃饭吃自己做的饭菜");
    }

    @Override
    public void code() {
        System.out.println("写前端代码");
    }

    @Override
    public void sleep() {
        System.out.println("10点睡觉");
    }
}

5.编码测试

测试编码:

public class Test {
    public static void main(String[] args) {
        //模板方法模式
        System.out.println("模板方法模式测试\n");


        System.out.println("小明的一天*****");
        Coder ming = new Ming();
        ming.TemplateMethod();//执行模板方法

        System.out.println();//换行

        System.out.println("小红的一天*****");
        Coder red = new Red();
        red.TemplateMethod();//执行模板方法
    }
}

测试结果:

模板方法模式测试

小明的一天*****
8点起床
吃饭吃的外卖
写后端代码
锻炼半小时
11点睡觉

小红的一天*****
7点起床
吃饭吃自己做的饭菜
写前端代码
锻炼半小时
10点睡觉

可看到按照抽象父类指定的顺序执行,子类只管实现方法,而不管各方法调用顺序流程。

6.模板模式中的钩子方法

试想一下这个场景:小明今天放假了,不写代码。(假设上班就写代码,不上班就不写代码)

那要如何改进上述的模板模式呢?

修改如下:

添加一个是否需要工作的方法(注意是具体的方法,不是抽象方法,这样子类可以选择性的重写),返回值为布尔类型,用true代表需要写代码,false代表不需要写代码。在模板方法中在原本需要执行code()方法的地方加入判断语句即可。

这种在模板模式中抽象父类中,一个默认不做任何事,子类可以选择性重写的方法,称为钩子方法

具体编码如下:

public abstract class Coder {
    public abstract void getup();//起床
    public abstract void eat();//吃饭
    public abstract void code();//写代码
    public abstract void sleep();//睡觉
    public void exercise(){
        System.out.println("锻炼半小时");
    }
    //模板(定义了各个方法的调用顺序和一些其他操作)
    public void TemplateMethod(){
        getup();
        eat();
        if (isWork()){
            code();//上班就写代码,不上班不写代码
        }
        exercise();
        sleep();
    }
    //钩子方法:判断是否上班
    public boolean isWork(){
        return true;//设置默认值
    }
}

小明的类需要重写该方法,并且返回false。

public class Ming extends Coder {

    //不上班
    @Override
    public boolean isWork() {
        return false;
    }

    @Override
    public void getup() {
        System.out.println("8点起床");
    }

    @Override
    public void eat() {
        System.out.println("吃饭吃的外卖");
    }

    @Override
    public void code() {
        System.out.println("写后端代码");
    }

    @Override
    public void sleep() {
        System.out.println("11点睡觉");
    }
}

测试代码不需要改变,测试结果为:

模板方法模式测试

小明的一天*****
8点起床
吃饭吃的外卖
锻炼半小时
11点睡觉

小红的一天*****
7点起床
吃饭吃自己做的饭菜
写前端代码
锻炼半小时
10点睡觉

可以看到,小明的一天就没有写代码了。而小红依然不变,而若小红也不需要写代码时,同样重写isWork()方法并返回false即可。

7.小结

使用场景:当要完成的一个过程它需要经过一系列步骤,而且一些步骤大致相同时,但其个别步骤实现可能不同,需要考虑模板方法模式。

优点:模板方法模式可以使 逻辑处理通用化,无需在每个类中写逻辑处理(如方法调用顺序),实现了代码复用。

发布了83 篇原创文章 · 获赞 40 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_42391904/article/details/104189212