设计模式 - Template Method 模板方法模式

简介

定义:模板方法设计模式是一种行为型设计模式,构建一个算法框架的方法,允许子类在维持算法整体结构不变的情况下,对算法的特定环节进行自定义实现。

是不是很蒙?当然定义是要结合实践去理解的。

使用场景:在重构的时候,发现写了两个或者多个几乎一样的类,只是有些方法的实现方式不一致,但是在使用这些类的地方调用方法顺序都一样,那就可以选择模板方法了!

UML类图

如上图所示,模板方法模式关键点如下:一个模板类`CoffeeMaker`,里面有一个定义为`final`的模板方法`makeCoffee()`。 多个模板实现类。

实例场景:
想象一下,你是一家咖啡连锁店的老板,你们有一套标准的咖啡制作流程:选择咖啡豆 -> 研磨咖啡豆 -> 冲泡咖啡 -> 添加调料 -> 拉花(钩子方法,可选)。其中冲泡咖啡是通用的逻辑,是每个咖啡制作的必然流程。而选择咖啡豆、研磨咖啡豆、添加调料每种咖啡制作流程是不一样的,最后有的咖啡需要拉花。

代码实现

第一步:定义模板类以及模板方法

先定义一个模板类`CoffeeMaker`,如下代码片段所示,其中的`makeCoffee()`就是所谓的模板方法,为了不被子类重写,它被设置为`final`的,其定义了一个算法骨架。

其中的`brewCoffee()`是一个实体方法,里面是通用逻辑,所有的子类都是一样的,所有咖啡都需要冲泡。三个被`abstract`修饰的是抽象方法,这些方法是需要子类去根据自己的实际算法实现的。

而`latteArt()`方法有一个默认的空实现,这个一般称为==钩子方法==,设计用来被其中部分需要的子类重写。例如卡布奇诺咖啡需要拉花,美式不需要拉花。那么卡布奇诺类重写`latteArt`方法即可

// 抽象类,定义了咖啡制作的模板方法
public abstract class CoffeeMaker {
    // 模板方法:定义了咖啡制作的固定步骤
    public final void makeCoffee() {
        chooseCoffeeBean();
        grindCoffeeBean();
        brewCoffee();
        addSeasoning();
        latteArt();
    }

    // 选择咖啡豆
    public abstract void chooseCoffeeBean();

    // 研磨咖啡豆
    public abstract void grindCoffeeBean();

    // 冲泡咖啡(默认实现,通用逻辑)
    private void brewCoffee() {
        System.out.println("冲泡咖啡");
    }

    // 添加调料,抽象方法,由子类实现
    public abstract void addSeasoning();

    /*钩子方法,可以被需要的子类overwrite*/
    //是否拉花
    public void latteArt() {
    }
}

第二步:定义具体的实体类,根据情况重写相应的抽象方法和钩子方法。

值得注意的是,由于卡布奇诺咖啡需要拉花,所以它重写了`latteArt()`这个钩子方法。美式咖啡不需要拉花,所以不用重写`latteArt()`这个方法,只需覆盖其他抽象方法即可。

// 子类,实现具体步骤
public class Cappuccino extends CoffeeMaker{
    @Override
    public void chooseCoffeeBean() {
        System.out.println("选择卡布奇诺咖啡豆");
    }

    @Override
    public void grindCoffeeBean() {
        System.out.println("研磨卡布奇诺咖啡豆");
    }

    @Override
    public void addSeasoning() {
        System.out.println("添加卡布奇诺调料");
    }

    @Override
    public void latteArt() {
        super.latteArt();
        System.out.println("卡布奇诺拉花~");
    }
}


public class Americano extends CoffeeMaker{
    @Override
    public void chooseCoffeeBean() {
        System.out.println("选择美式咖啡豆");
    }

    @Override
    public void grindCoffeeBean() {
        System.out.println("研磨美式咖啡豆");
    }

    @Override
    public void addSeasoning() {
        System.out.println("添加美式调料");
    }
}

第三步:客户端调用

// 客户端代码
public class CoffeeShop {
    public static void main(String[] args) {
        Cappuccino cappuccino = new Cappuccino();
        cappuccino.makeCoffee();

        System.out.println("----------------");

        Americano americano = new Americano();
        americano.makeCoffee();
    }
}

结果显示:从输出可以清楚的看到,要做哪种咖啡就实例哪种咖啡的对象,但是大致流程都是一样的。

选择卡布奇诺咖啡豆
研磨卡布奇诺咖啡豆
冲泡咖啡
添加卡布奇诺调料
卡布奇诺拉花~
----------------
选择美式咖啡豆
研磨美式咖啡豆
冲泡咖啡
添加美式调料

总结

优点:

代码复用:模板方法模式让你能够复用代码,减少重复。
可扩展性:子类可以很容易地扩展或修改算法的特定步骤。

缺点:
类数量增加:每个不同的实现都需要一个子类,这可能会增加系统中类的总数。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值