“补课”进行时:设计模式(3)——和做菜一样简单的模版方法模式

1. 前文汇总

“补课”进行时:设计模式系列

2. 做菜?

做菜大致需要几个步骤?

  1. 洗菜
  2. 切菜
  3. 起锅烧油
  4. 装盘

剩下的就可以吃了,对吧~~~

现在,我们要做一个番茄炒蛋,就下面这货:

  • 第一步:先把番茄洗干净去皮。
  • 第二步:番茄切好,鸡蛋打散。
  • 第三步:起锅烧油,一顿翻炒。
  • 第四步:装盘,大功告成。

这件事情我用程序实现下,先抽象一个做菜的模型:

public abstract class AbstractCook {
    /**
     * 做菜第一步就是先洗菜
     */
    public abstract void xicai();

    /**
     * 菜洗完了以后要切菜
     */
    public abstract void qiecai();

    /**
     * 然后就是起锅烧油,写到这的时候满脑子德子的声音
     */
    public abstract void qiguoshaoyou();

    /**
     * 菜烧好以后需要装盘就能上桌了
     */
    public abstract void zhuangpan();

    /**
     * 开始做菜
     */
    public abstract void cook();
}

然后开始番茄炒蛋:

public class TomatoEggs extends AbstractCook {
    @Override
    public void xicai() {
        System.out.println("番茄炒蛋先洗菜");
    }

    @Override
    public void qiecai() {
        System.out.println("番茄炒蛋再切菜");
    }

    @Override
    public void qiguoshaoyou() {
        System.out.println("现在开始起锅烧油做番茄炒蛋");
    }

    @Override
    public void zhuangpan() {
        System.out.println("番茄炒蛋烧好以后装盘");
    }

    @Override
    public void cook() {
        this.xicai();
        this.qiecai();
        this.qiguoshaoyou();
        this.zhuangpan();
    }
}

做完了番茄炒蛋,感觉有点不够吃,再来一个宫保鸡丁:

public class KungPaoChicken extends AbstractCook {
    @Override
    public void xicai() {
        System.out.println("宫保鸡丁先洗菜");
    }

    @Override
    public void qiecai() {
        System.out.println("宫保鸡丁再切菜");
    }

    @Override
    public void qiguoshaoyou() {
        System.out.println("现在开始起锅烧油做宫保鸡丁");
    }

    @Override
    public void zhuangpan() {
        System.out.println("宫保鸡丁烧好以后装盘");
    }

    @Override
    public void cook() {
        this.xicai();
        this.qiecai();
        this.qiguoshaoyou();
        this.zhuangpan();
    }
}

程序写到这里,好像有哪里不对,两个实现类的 cook() 方法都是完全相同的,那这个 cook() 方法的实现应该出现在抽象类,不应该在实现类上,抽象是所有子类的共性封装。

代码修改一下,把刚才做菜的那个抽象模型修改一下:

public abstract class AbstractCook {
    /**
     * 做菜第一步就是先洗菜
     */
    public abstract void xicai();

    /**
     * 菜洗完了以后要切菜
     */
    public abstract void qiecai();

    /**
     * 然后就是起锅烧油,写到这的时候满脑子德子的声音
     */
    public abstract void qiguoshaoyou();

    /**
     * 菜烧好以后需要装盘就能上桌了
     */
    public abstract void zhuangpan();

    /**
     * 开始做菜,在抽象类里直接定义执行过程
     */
    public void cook(){
        this.xicai();
        this.qiecai();
        this.qiguoshaoyou();
        this.zhuangpan();
    }
}

输出结果:

番茄炒蛋先洗菜
番茄炒蛋再切菜
现在开始起锅烧油做番茄炒蛋
番茄炒蛋烧好以后装盘

好了,这就是模版方法模式,是不是感觉很简单,经常会见到或者经常会用到。对的,没毛病,你经常在使用,但你不知道这是模板方法模式,

3. 定义

模板方法模式(Template Method Pattern):

Define the skeleton of an algorithm in an operation,deferring some steps tosubclasses.Template Method lets subclasses redefine certain steps of analgorithm without changing the algorithm’s structure.(定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。)

在这张类图里面, AbstractClass 叫做抽象模板,它的方法分为两类:

  • 基本方法:由子类实现,并且在模板方法被调用。
  • 模板方法:可以有一个或几个,一般是一个具体方法,也就是一个框架,实现对基本方法的调度,完成固定的逻辑。

为了防止恶意的操作,一般模板方法都加上final关键字,不允许被覆写。

下面是模版方法模式的通用代码:

抽象模板类:

public abstract class AbstractClass {
    // 基本方法
    protected abstract void doSomething();
    // 基本方法
    protected abstract void doAnything();
    // 模板方法
    public final void templateMethod() {
        this.doSomething();
        this.doAnything();
    }
}

具体模板类:

public class ConcreteClass1 extends AbstractClass {
    @Override
    protected void doSomething() {
        // 逻辑处理
    }

    @Override
    protected void doAnything() {
        // 逻辑处理
    }
}

public class ConcreteClass2 extends AbstractClass {
    @Override
    protected void doSomething() {
        // 逻辑处理
    }

    @Override
    protected void doAnything() {
        // 逻辑处理
    }
}

优点:

  • 封装不变部分,扩展可变部分。
  • 提取公共部分代码,便于维护。
  • 行为由父类控制,子类实现。