【设计模式】我觉得Java程序员不需要学模板方法模式,你觉得呢?

611 阅读4分钟

这是我参与8月更文挑战的第2天,活动详情查看:8月更文挑战

什么是模板方法模式(Template Method)

概念

模板方法模式(Template Method)属于行为型模式,这个模式的名称听着有点让人摸不着头脑。模板方法模式是指在抽象类中定义一个非抽象方法,在这个非抽象方法中定义好如何调用抽象方法,而这些抽象方法实现交给子类去完成,相当于父类定好了框架,子类负责实现这个框架的内容

在面向对象语言中,我们如何使用抽象类,并在其中定义非抽象方法和抽象方法,模板方法模式给出了一个可以提供我们模仿的规范。

现实生活中也有非常多这样的例子,像一台电脑,电脑主板已经固定好要什么东西了,CPU、硬盘、内存条,这些我们都可以自己去组装;还有画画,一般都是先画一个基本的框架,剩下的细节和上色,不同人来画都有可能不同。

我是自愿上班的

优点

  1. 符合开放封闭原则。想要实现不同的功能,只需要实现不同的子类即可,提高了系统的扩展性。
  2. 父类提取了复用的代码,提高了代码的复用性和可维护性。

缺点

  1. 提高了类间的耦合度。因为是使用继承的方式来实现的,当抽象类新增了一个抽象方法,所有子类也得新增。
  2. 提高了代码的阅读难度。这是一种反向的控制结构,一般情况下是子类调用父类中的方法,而这里是父类调用子类的方法,这也让我们的设计更加的抽象,也更难的读懂。

所有设计模式都是在合适的场景使用才会有奇效,强行使用只会适得其反。

原则

“+”代表遵守,“-”代表不遵守或者不相关

原则开放封闭单一职责迪米特里氏替换依赖倒置接口隔离合成复用
++-++--

适用场景

  1. 多个子类中有相同的方法,逻辑基本相同。
  2. 一个方法的基本逻辑/主体架构是确定的,但有些地方会进场变动。

如何实现

想要实现模板方法模式,需要以下两样东西:

  1. 模板方法:抽象类中的非抽象方法,定义基本的逻辑骨架,调用基本方法的顺序以及处理操作。
  2. 基本方法: 抽象方法:在抽象类中声明,由子类实现。 非抽象方法:在抽象类中已经实现,子类继承。 钩子方法:在抽象类中空实现的方法,子类可以不实现。

类图

这里贴个模板方法模式的类图

模板方法类图

在TemplateMethod中就定义了其他方法的调用顺序。

例子

我们都经常去喝奶茶,那么热的天没有什么比喝一杯冰冰凉凉的奶茶舒服了,如果有,那一定是冰可乐。

小鸡带可乐

做奶茶一般都是有一个固定的步骤的,加奶茶粉、加水、加糖&调料、摇、加冰、打包,这就是一个模板,这里的步骤有些是不变的,有些是根据客人的要求来定的,我们去买奶茶可以定几分糖、少冰多冰。

类图

image-20210609164041138

代码

奶茶抽象类:定义模板方法、抽象方法和非抽象方法

/**
 * 奶茶抽象类
 *
 * @author xuxiaobai
 */
abstract class MilkyTea{
    /**
     * 做奶茶
     * 模板方法最好加个final
     */
    final void process(){
        addTeaPowderWithMilk();
        addSugarAndCondiment();
        addWrite();
        shake();
        addIce();
        pack();
    }
​
    /**
     * 加奶茶粉
     */
    abstract void addTeaPowderWithMilk();
​
    /**
     * 加糖浆和调料
     */
    abstract void addSugarAndCondiment();
​
    /**
     * 加水
     */
    void addWrite(){
        System.out.println("加水");
    }
​
    void shake(){
        System.out.println("使劲摇");
    }
​
    abstract void addIce();
​
    void pack(){
        System.out.println("封口");
        System.out.println("装袋");
        System.out.println("完成");
    }
}
​

无糖多冰绿奶茶:实现抽象方法

/**
 * 无糖多冰绿奶茶
 *
 * @author xuxiaobai
 */
public class NoSugarManyIceGreetMilkyTea extends MilkyTea {
    @Override
    void addTeaPowderWithMilk() {
        System.out.println("加绿茶粉&奶");
    }
​
    @Override
    void addSugarAndCondiment() {
        System.out.println("不加糖");
    }
​
    @Override
    void addIce() {
        System.out.println("加半杯冰");
    }
}
​

测试类:

/**
 *
 * @author xuxiaobai
 */
public class TemplateMethodTest {
    public static void main(String[] args) {
        //现想要一个无糖多冰绿奶茶
        MilkyTea milkyTea=new NoSugarManyIceGreetMilkyTea();
        //开始制作
        System.out.println("---无糖多冰绿奶茶制作过程---");
        milkyTea.process();
        /**
         * 结果:
         * ---无糖多冰绿奶茶制作过程---
         * 加绿茶粉&奶
         * 不加糖
         * 加水
         * 使劲摇
         * 加半杯冰
         * 封口
         * 装袋
         * 完成
         */
    }
}

这里简单地写了一个无糖多冰绿奶茶类,这里的很多方法都是在抽象类中直接使用,然后实现类去实现,你大概体会一下模板方法的使用即可。

小鸡喝可乐

总结

模板方法模式提供了反向控制结构的指导,定义了抽象类中的方法怎么和实现类的方法去交互。其实也不需要特别地去记这个设计模式,只要知道在抽象类中,非抽象方法可以使用抽象方法,抽象方法呢又需要子类去实现,就可以了,到了特定的情况,在做代码优化的时候自然而然地就会使用模板方法模式了。

小鸡摇屁股

\