模板方法模式(Template Method Pattern)

本文深入探讨了模板方法模式的定义、实现及其在准备咖啡和柠檬茶等饮品中的应用,通过逐步提炼和抽象,展示了如何简化代码结构并实现流程控制的灵活性与可控性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

模板方法模式定义:在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的条件下,重新定义算法中的某些步骤

准备一杯咖啡:加咖啡粉 - 加热水 - 冲泡 - 加糖


public class Coffee {

    public void addCoffeePowder(){
        System.out.println("加咖啡粉");
    }

    public void addHotWater(){
        System.out.println("加热水");
    }

    public void brew(){
        System.out.println("冲泡");
    }

    public void addSugar(){
        System.out.println("加糖");
    }

    public void prepareCoffee(){
        addCoffeePowder();
        addHotWater();
        brew();
        addSugar();
    }
}

准备一杯柠檬茶也差不多是同样的步骤:加茶叶 - 加热水 - 冲泡 - 加柠檬汁


public class LemonTea {

    public void addTea(){
        System.out.println("加茶叶");
    }

    public void addHotWater(){
        System.out.println("加热水");
    }

    public void brew(){
        System.out.println("冲泡");
    }

    public void addLemonJuice(){
        System.out.println("加柠檬汁");
    }

    public void prepareLemonTea(){
        addTea();
        addHotWater();
        brew();
        addLemonJuice();
    }
}

抽象出共同的父类,将相同的方法移动至父类中:


public class Beverage {

    public void addHotWater(){
        System.out.println("加热水");
    }

    public void brew(){
        System.out.println("冲泡");
    }
}
public class Coffee extends Beverage {

    public void addCoffeePowder(){
        System.out.println("加咖啡粉");
    }

    public void addSugar(){
        System.out.println("加糖");
    }

    public void prepareCoffee(){
        addCoffeePowder();
        addHotWater();
        brew();
        addSugar();
    }
}
public class LemonTea extends Beverage {

    public void addTea(){
        System.out.println("加茶叶");
    }

    public void addLemonJuice(){
        System.out.println("加柠檬汁");
    }

    public void prepareLemonTea(){
        addTea();
        addHotWater();
        brew();
        addLemonJuice();
    }
}

简洁多了,但是仔细观察,加咖啡与加茶叶可以抽象为加主料,加糖与加柠檬汁可以抽象为加配料方法:

public abstract class Beverage {

    public abstract void addIngredient();

    public void addHotWater(){
        System.out.println("加热水");
    }

    public void brew(){
        System.out.println("冲泡");
    }

    public abstract void addCondiment();
}
public class Coffee extends Beverage {

    public void addIngredient(){
        System.out.println("加咖啡粉");
    }

    public void addCondiment(){
        System.out.println("加糖");
    }

    public void prepareCoffee(){
        addIngredient();
        addHotWater();
        brew();
        addCondiment();
    }
}
public class LemonTea extends Beverage {

    public void addIngredient(){
        System.out.println("加茶叶");
    }

    public void addCondiment(){
        System.out.println("加柠檬汁");
    }

    public void prepareLemonTea(){
        addIngredient();
        addHotWater();
        brew();
        addCondiment();
    }
}

此时已经可以清楚的发现,prepareCoffee与prepareLemonTea方法所包含的步骤是完全一样的,可以移动至共同父类中


public abstract class Beverage {

    public abstract void addIngredient();

    public void addHotWater(){
        System.out.println("加热水");
    }

    public void brew(){
        System.out.println("冲泡");
    }

    public abstract void addCondiment();

    public void prepareBeverage(){
        addIngredient();
        addHotWater();
        brew();
        addCondiment();
    }
}
public class Coffee extends Beverage {

    public void addIngredient(){
        System.out.println("加咖啡粉");
    }

    public void addCondiment(){
        System.out.println("加糖");
    }
}
public class LemonTea extends Beverage {

    public void addIngredient(){
        System.out.println("加茶叶");
    }

    public void addCondiment(){
        System.out.println("加柠檬汁");
    }
}

可以看到现在整个代码的结构已经完全符合模板方法模式的定义了

整体冲泡流程由父类的prepareBeverage方法控制,该方法为所有的子类提统一的固定的准备流程,这里面固定的流程即为模板方法模式定义中的算法骨架

子类可以在不改变算法流程的条件下,重新定义算法中的某些步骤,如:冲泡不同饮品时需要加的主配料由特定饮品类实现

如果准备咖啡需要特定的流程,只需在Coffee类中重写Beverage的prepareBeverage方法即可

如果想要Beverage类所有子类的准备流程完全一致(严格按照加主料 - 加水 - 冲泡 - 加配料这一流程),且不允许修改,只需使用final修饰Beverage类的prepareBeverage方法即可

上面的设计对流程的控制太过严苛,很难在实际应用中使用,当然通过一些改动,使子类除了能够决定特定步骤的具体实现方式之外,还可以对流程进行控制

---- 2018-06-02

灵活,但是将使算法结构变得复杂混乱

如果需要大量这种改动,说明在当前业务场景下,模板方法模式并不是最好的选择,建造者模式可能是更好的选择


public abstract class Beverage {

    public abstract void addIngredient();

    public void addHotWater(){
        System.out.println("加热水");
    }

    public void brew(){
        System.out.println("冲泡");
    }

    public abstract void addCondiment();

    protected boolean addOrNot(){
        return true;
    }

    public void prepareBeverage(){
        addIngredient();
        addHotWater();
        brew();
        if(addOrNot())
            addCondiment();
    }
}
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Coffee extends Beverage {

    public void addIngredient(){
        System.out.println("加咖啡粉");
    }

    public void addCondiment(){
        System.out.println("加糖");
    }

    protected boolean addOrNot(){
        try {
            System.out.println("Have some sugar?Y/N");
            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
            String in = reader.readLine();
            if(null == in || in.equals("") || in.equals("N")){
                return false;
            }
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }
}

测试一下:

public class Test {
    public static void main(String[] args) {
        Beverage b = new Coffee();
        b.prepareBeverage();
    }
}

测试结果如下:

加咖啡粉
加热水
冲泡
Have some sugar?Y/N
Y
加糖
加咖啡粉
加热水
冲泡
Have some sugar?Y/N
N


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值