md_files/自学/草稿.md

160 lines
5.4 KiB
Markdown
Raw Normal View History

### 一、策略模式 (Strategy)
**核心思想**
把可互换的算法/行为抽成独立策略类,运行时由“上下文”对象选择合适的策略;对调用方来说,只关心统一接口,而非具体实现。
```
┌───────────────┐
│ Client │
└─────▲─────────┘
│ has-a
┌─────┴─────────┐ implements
│ Context │────────────┐ ┌──────────────┐
│ (使用者) │ strategy └─▶│ Strategy A │
└───────────────┘ ├──────────────┤
│ Strategy B │
└──────────────┘
```
#### Demo支付策略Java
```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
```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 容器负责策略注册/发现。
这样即可同时获得“纵向流程复用”+“横向算法可插拔”的双重优势。