md_files/自学/草稿.md

5.4 KiB
Raw Permalink Blame History

一、策略模式 (Strategy)

核心思想 把可互换的算法/行为抽成独立策略类,运行时由“上下文”对象选择合适的策略;对调用方来说,只关心统一接口,而非具体实现。

┌───────────────┐
│   Client      │
└─────▲─────────┘
      │ has-a
┌─────┴─────────┐                 implements
│  Context      │────────────┐  ┌──────────────┐
│ (使用者)      │ strategy    └─▶│ Strategy A   │
└───────────────┘                ├──────────────┤
                                 │ Strategy B   │
                                 └──────────────┘

Demo支付策略Java

// 1. 抽象策略
public interface PayStrategy {
    void pay(int cents);
}

// 2. 具体策略
public class AliPay implements PayStrategy {
    public void pay(int cents) { System.out.println("Alipay ¥" + cents / 100.0); }
}
public class WxPay implements PayStrategy  {
    public void pay(int cents) { System.out.println("WeChat Pay ¥" + cents / 100.0); }
}

// 3. 上下文
public class PaymentService {
    private final PayStrategy strategy;
    public PaymentService(PayStrategy strategy) { this.strategy = strategy; }
    public void checkout(int cents) { strategy.pay(cents); }
}

// 4. 运行时选择策略
public class Demo {
    public static void main(String[] args) {
        PaymentService ps1 = new PaymentService(new AliPay());
        ps1.checkout(2599);          // Alipay ¥25.99

        PaymentService ps2 = new PaymentService(new WxPay());
        ps2.checkout(4999);          // WeChat Pay ¥49.99
    }
}

要点

  • 开放封闭:新增 PayPal 只需实现 PayStrategy,无须改 PaymentService
  • 运行期切换:可根据配置、用户偏好等动态注入不同策略。

二、模板方法模式 (Template Method)

核心思想 在抽象父类中定义算法骨架(固定执行顺序),把某些可变步骤留给子类重写;调用方只用模板方法,保证流程一致。

 Client  ───▶  AbstractClass
                ├─ templateMethod()  ←—— 固定流程
                │    step1()
                │    step2()         ←—— 抽象,可变
                │    step3()
                └─ hookMethod()      ←—— 可选覆盖
                       ▲
                       │ extends
            ┌──────────┴──────────┐
            │ ConcreteClassA/B…   │

Demo弹窗加载流程Java

// 1. 抽象模板
public abstract class AbstractDialog {

    // 模板方法:固定调用顺序,设为 final 防止子类改流程
    public final void show() {
        initLayout();
        bindEvent();
        beforeDisplay();       // 钩子,可选
        display();
        afterDisplay();        // 钩子,可选
    }

    // 具体公共步骤
    private void initLayout() {
        System.out.println("加载通用布局文件");
    }

    // 需要子类实现的抽象步骤
    protected abstract void bindEvent();

    // 钩子方法,默认空实现
    protected void beforeDisplay() {}
    protected void afterDisplay() {}

    private void display() {
        System.out.println("弹出对话框");
    }
}

// 2. 子类:登录对话框
public class LoginDialog extends AbstractDialog {
    @Override
    protected void bindEvent() {
        System.out.println("绑定登录按钮事件");
    }
    @Override
    protected void afterDisplay() {
        System.out.println("focus 到用户名输入框");
    }
}

// 3. 调用
public class Demo {
    public static void main(String[] args) {
        AbstractDialog dialog = new LoginDialog();
        dialog.show();
        /* 输出:
           加载通用布局文件
           绑定登录按钮事件
           弹出对话框
           focus 到用户名输入框
         */
    }
}

要点

  • 复用公共流程initLayout()display() 写一次即可。
  • 限制流程顺序show() 定为 final,防止子类乱改步骤。
  • 钩子方法:子类可选择性覆盖(如 beforeDisplay)。

关键区别 & 组合用法

策略模式 模板方法模式
目的 横向扩展——允许算法并列互换 纵向复用——抽取算法骨架,固定顺序
实现方式 组合 + 接口 继承 + 抽象父类
行为选择时机 运行时由外部注入 编译期由继承确定
常组合 工厂模式配合选择策略 钩子方法回调一起用

在实际项目中,两者经常组合

折扣计算 Strategy → 公共过滤 & 日志 Template Method → Spring 容器负责策略注册/发现。

这样即可同时获得“纵向流程复用”+“横向算法可插拔”的双重优势。