md_files/自学/草稿.md

160 lines
5.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

### 一、策略模式 (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 容器负责策略注册/发现。
这样即可同时获得“纵向流程复用”+“横向算法可插拔”的双重优势。