【Java学习】【Java基础】--第3篇:初学模板方法模式和策略模式

一、模板方法模式 (Template Method Pattern)

1. 核心思想:骨架不变,细节可变

2. 模板方法模式的关键特点

  1. 控制流程:父类控制算法骨架,子类实现具体步骤
  2. 代码复用:公共代码在抽象类中实现
  3. 扩展性:通过钩子方法提供灵活性
  4. 好莱坞原则:"不要调用我们,我们会调用你" - 子类不直接调用父类,而是父类调用子类(父类决定了流程,子类决定了细节)

假设要开一家饮品店,制作饮料有固定的流程,但具体步骤可以调整。

3. 模式结构

// 抽象类 - 定义饮料制作模板
abstract class BeverageTemplate {

    // 模板方法 - final防止子类改变算法骨架
    public final void prepareBeverage() {
        boilWater();
        brew();
        pourInCup();
        if (customerWantsCondiments()) {
            addCondiments();
        }
        serve();
    }

    // 固定步骤,子类共享
    private void boilWater() {
        System.out.println("烧开水");
    }

    private void pourInCup() {
        System.out.println("倒入杯中");
    }

    private void serve() {
        System.out.println("端给顾客");
    }

    // 抽象方法 - 由子类实现具体细节
    protected abstract void brew();
    protected abstract void addCondiments();

    // 钩子方法,子类可以选择重写
    protected boolean customerWantsCondiments() {
        return true; // 默认加调料
    }
}

4. 具体实现

// 咖啡具体实现
class Coffee extends BeverageTemplate {
    @Override
    protected void brew() {
        System.out.println("冲泡咖啡");
    }

    @Override
    protected void addCondiments() {
        System.out.println("添加糖和牛奶");
    }

    @Override
    protected boolean customerWantsCondiments() {
        // 模拟部分顾客需要添加调料
        return Math.random() > 0.5;
    }
}

// 茶具体实现
class Tea extends BeverageTemplate {
    @Override
    protected void brew() {
        System.out.println("浸泡茶叶");
    }

    @Override
    protected void addCondiments() {
        System.out.println("添加柠檬");
    }
}

public class Main {
    public static void main(String[] args) {

        System.out.println("制作咖啡");
        Coffee coffee = new Coffee();
        coffee.prepareBeverage();
        
        // 制作咖啡
        // 烧开水
        // 冲泡咖啡
        // 倒入杯中
        // 添加糖和牛奶
        // 端给顾客
        
        System.out.println();
        System.out.println("制作茶饮");
        Tea tea = new Tea();
        tea.prepareBeverage();
        
        // 制作茶饮
        // 烧开水
        // 浸泡茶叶
        // 倒入杯中
        // 添加柠檬
        //端给顾客
    }
}

二、策略模式 (Strategy Pattern)

1. 核心思想:定义算法家族,让它们可以互相替换

2. 策略模式的关键特点

  1. 开闭原则:无需修改上下文即可引入新策略
  2. 消除条件语句:用多态代替复杂的条件判断
  3. 代码复用:可以在不同上下文中复用一个策略
  4. 灵活性:运行时动态切换算法
  5. 单一职责:每个算法都有自己的类

假设要实现一个支付系统,支持多种支付方式,每种支付方式的算法不同。

3. 模式结构

// 策略接口 - 定义所有支付方式的共同行为
interface PaymentStrategy {
    void pay(double amount);
    boolean validate();
}

// 具体实现 - 信用卡支付
class CreditCardPayment implements PaymentStrategy {

    // 信用卡号
    private String cardNumber;

    public CreditCardPayment(String cardNumber) {
        this.cardNumber = cardNumber;
    }

    @Override
    public void pay(double amount) {
        System.out.println("使用信用卡支付" + amount + "元");
        System.out.println("卡号: ****-****-****-" + maskCardNumber());
    }

    @Override
    public boolean validate() {
        return cardNumber != null && cardNumber.length() == 16;
    }

    private String maskCardNumber() {
        return cardNumber.substring(12);
    }
}

// 具体实现 - 支付宝支付
class AlipayPayment implements PaymentStrategy {

    private String account;

    public AlipayPayment(String account) {
        this.account = account;
    }

    @Override
    public void pay(double amount) {
        System.out.println("使用支付宝支付" + amount + "元");
        System.out.println("账户: " + account);
    }

    @Override
    public boolean validate() {
        return account != null && account.contains("@");
    }
}

4. 上下文类 - 使用策略:

// 支付上下文 - 负责使用策略
class PaymentContext {
    private PaymentStrategy paymentStrategy;
    private String orderId;

    public PaymentContext(String orderId) {
        this.orderId = orderId;
    }

    // 设置策略
    public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
        this.paymentStrategy = paymentStrategy;
    }

    // 执行支付
    public boolean executePayment(double amount) {
        if (paymentStrategy == null) {
            System.out.println("请设置支付模式!");
            return false;
        }

        if (!paymentStrategy.validate()) {
            System.out.println("验证失败!");
            return false;
        }

        System.out.println("开始处理订单" + orderId);
        paymentStrategy.pay(amount);
        System.out.println("支付成功");
        return true;
    }
}

public class Main {
    public static void main(String[] args) {

        String orderId = "ABC_12345";
        PaymentContext paymentContext = new PaymentContext(orderId);

        // 使用信用卡策略
        System.out.println("===使用信用卡支付===");
        paymentContext.setPaymentStrategy(new CreditCardPayment("1234567891011121"));
        paymentContext.executePayment(100.0);

        // ===使用信用卡支付===
        // 开始处理订单ABC_12345
        // 使用信用卡支付100.0元
        // 卡号: ****-****-****-1121
        // 支付成功

        // 使用支付宝策略
        System.out.println("\n===使用支付宝支付===");
        paymentContext.setPaymentStrategy(new AlipayPayment("user@alipay.com"));
        paymentContext.executePayment(25.0);

        // ===使用支付宝支付===
        // 开始处理订单ABC_12345
        // 使用支付宝支付25.0元
        // 账户: user@alipay.com
        // 支付成功
    }
}

三、深入对比分析

1. 设计目标不同

方面 模板方法模式 策略模式
关注点 算法步骤的固定与变化 算法实现的互换性
关系 父子类继承关系 接口与实现关系
控制权 父类控制流程 客户端控制选择

2. 代码结构对比

模板方法模式:

abstract class Processor {
    public final void process() {  // 固定流程
        step1();
        step2();  // 抽象方法
        step3();
    }
    private void step1() { /* 实现 */ }
    protected abstract void step2();
    private void step3() { /* 实现 */ }
}

策略模式:

interface Strategy {
    void execute();
}

class Context {
    private Strategy strategy;
    public void setStrategy(Strategy s) { 
        this.strategy = s; 
    }
    public void execute() { 
        strategy.execute();  // 委托给策略
    }
}

四、两者结合

模板方法模式定义数据处理框架

abstract class DataProcessor {
    // 父类决定流程
    public final void process(String input) {
        if (!validateInput(input)) {
            System.out.println("输入不得为空!");
            return;
        }
        String data = transformData(input);
        outResult(data);
    }

    // 抽象方法 - 子类具体实现数据转换
    protected abstract String transformData(String input);

    private boolean validateInput(String input) {
        return input != null && !input.trim().isEmpty();
    }

    private void outResult(String data) {
        System.out.println("输出:" + data);
    }

}

策略模式提供不同的转换实现

interface TransformStrategy {
    String transform(String input);
}

class UppercaseStrategy implements TransformStrategy {
    @Override
    public String transform(String input) {
        return input.toUpperCase();
    }
}

class ReverseStrategy implements TransformStrategy {
    @Override
    public String transform(String input) {
        return new StringBuilder(input).reverse().toString();
    }
}

结合两种方法

class StrategyProcessor extends DataProcessor {

    private TransformStrategy strategy;

    // 可以在运行时改变策略
    public void setStrategy(TransformStrategy strategy) {
        this.strategy = strategy;
    }

    @Override
    protected String transformData(String input) {
        return strategy.transform(input);
    }
}

public class Main {

    public static void main(String[] args) {
        StrategyProcessor strategyProcessor = new StrategyProcessor();

        String input = "hello world";
        // 策略1
        strategyProcessor.setStrategy(new UppercaseStrategy());
        strategyProcessor.process(input); // 输出:HELLO WORLD

        // 策略2
        strategyProcessor.setStrategy(new ReverseStrategy());
        strategyProcessor.process(input); // 输出:dlrow olleh
    }

}

五、总结对比表

维度 模板方法模式 策略模式
核心思想 固定流程,可变步骤 算法互换,独立封装
关系类型 继承关系 组合关系
控制方向 父类控制子类 客户端控制算法
代码复用 通过继承复用模板代码 通过组合复用策略
灵活性 编译时确定算法结构 运行时切换算法
适用场景 算法骨架固定,步骤可变 多种算法需要动态选择
典型应用 框架、工作流、测试生命周期 支付方式、排序算法、压缩算法

选择指南:

  • 用模板方法当:你有固定的工作流程,但某些步骤需要定制化
  • 用策略模式当:你有多种算法,需要在运行时灵活切换
  • 结合使用当:既有固定流程,又需要在某些步骤使用不同策略
posted @ 2025-11-27 04:30  JustForFun1  阅读(4)  评论(0)    收藏  举报