文章目录
-
- 前言
- [1. 策略模式是什么?](#1. 策略模式是什么?)
- [2. 策略模式解决什么问题?](#2. 策略模式解决什么问题?)
- [3. 核心结构](#3. 核心结构)
-
- [3.1 Strategy(抽象策略)](#3.1 Strategy(抽象策略))
- [3.2 ConcreteStrategy(具体策略)](#3.2 ConcreteStrategy(具体策略))
- [3.3 Context(上下文)](#3.3 Context(上下文))
- [4. 实现思路](#4. 实现思路)
- [5. 示例](#5. 示例)
-
- [5.1 Strategy:抽象策略](#5.1 Strategy:抽象策略)
- [5.2 ConcreteStrategy:具体策略](#5.2 ConcreteStrategy:具体策略)
-
- [5.2.1 满减策略](#5.2.1 满减策略)
- [5.2.2 会员折扣策略](#5.2.2 会员折扣策略)
- [5.2.3 阶梯价策略](#5.2.3 阶梯价策略)
- [5.3 Context:上下文](#5.3 Context:上下文)
- [5.4 Client:客户端选择策略并调用](#5.4 Client:客户端选择策略并调用)
- [6. 优缺点](#6. 优缺点)
-
- [6.1 优点](#6.1 优点)
- [6.2 缺点](#6.2 缺点)
- [7. 和其他模式怎么区分?](#7. 和其他模式怎么区分?)
-
- [7.1 策略 vs 简单工厂/工厂方法](#7.1 策略 vs 简单工厂/工厂方法)
- [7.2 策略 vs 模板方法](#7.2 策略 vs 模板方法)
- [7.3 策略 vs 状态模式](#7.3 策略 vs 状态模式)
- [8. 适用场景](#8. 适用场景)
- [9. 总结](#9. 总结)
前言
在很多业务系统里,我们经常会遇到"同一类事情,不同情况下用不同算法/规则"的需求,比如:
- 支付方式不同(支付宝/微信/银行卡/积分)
- 价格计算不同(满减、折扣、阶梯价、会员价)
- 消息发送不同(短信/邮件/推送)
- 文件处理不同(压缩算法/加密算法/校验算法)
这些场景通常有一个共同点:算法会变,但调用方希望保持稳定 。
策略模式(Strategy Pattern)要解决的核心就是:
把算法/规则从使用它的代码中剥离出来,让它们以"可替换"的方式独立变化;客户端只依赖统一的抽象接口。
1. 策略模式是什么?
策略模式是一种行为型设计模式,通过"封装一组可复用的算法",并让它们都实现同一个接口,从而做到:
- 客户端根据条件选择合适的策略
- 后续新增/修改策略时,不需要改动客户端的大结构(遵循开闭原则)
2. 策略模式解决什么问题?
- 同一业务流程里会出现多个分支(if/else 很多)
- 算法(或规则)经常变化,且变化频率高
- 不希望改动调用方逻辑,只希望替换不同实现
- 希望代码结构更清晰、可扩展
如果代码里出现"根据类型/条件选择不同计算方式"的分支,而且会不断增多,就很适合策略模式。
3. 核心结构
3.1 Strategy(抽象策略)
定义策略必须实现的方法,例如 calculatePrice(...)。
3.2 ConcreteStrategy(具体策略)
多个具体类实现同一接口,对应不同算法或规则。
3.3 Context(上下文)
上下文类持有 Strategy,负责"在合适时机调用策略"。
4. 实现思路
按你给的享元模式示例那种"拆角色 + 实现 + 示例"的思路,策略模式通常是:
- 定义
Strategy接口(统一方法签名) - 写多个
ConcreteStrategy(不同算法) - 写
Context,构造时注入策略,或运行时切换 - 客户端只跟
Context或Strategy交互,不关心具体算法细节
5. 示例
不同规则计算价格
5.1 Strategy:抽象策略
java
public interface PricingStrategy {
double calculate(double originalPrice);
}
5.2 ConcreteStrategy:具体策略
5.2.1 满减策略
java
public class DiscountByCouponStrategy implements PricingStrategy {
@Override
public double calculate(double originalPrice) {
// 假设满100减20
if (originalPrice >= 100) {
return originalPrice - 20;
}
return originalPrice;
}
}
5.2.2 会员折扣策略
java
public class MemberDiscountStrategy implements PricingStrategy {
@Override
public double calculate(double originalPrice) {
// 会员9折
return originalPrice * 0.9;
}
}
5.2.3 阶梯价策略
java
public class TieredPricingStrategy implements PricingStrategy {
@Override
public double calculate(double originalPrice) {
// 假设阶梯:>=200打8折,>=100打9折,否则原价
if (originalPrice >= 200) return originalPrice * 0.8;
if (originalPrice >= 100) return originalPrice * 0.9;
return originalPrice;
}
}
5.3 Context:上下文
java
public class ShoppingCart {
private final PricingStrategy strategy;
public ShoppingCart(PricingStrategy strategy) {
this.strategy = strategy;
}
public double checkout(double originalPrice) {
return strategy.calculate(originalPrice);
}
}
5.4 Client:客户端选择策略并调用
java
public class Client {
public static void main(String[] args) {
double price = 150;
ShoppingCart cart1 = new ShoppingCart(new DiscountByCouponStrategy());
System.out.println("券后价格: " + cart1.checkout(price));
ShoppingCart cart2 = new ShoppingCart(new MemberDiscountStrategy());
System.out.println("会员价: " + cart2.checkout(price));
ShoppingCart cart3 = new ShoppingCart(new TieredPricingStrategy());
System.out.println("阶梯价: " + cart3.checkout(price));
}
}
会发现:
- "选择哪种计算方式"的逻辑被独立出来了(策略类)
ShoppingCart不关心具体算法,只负责调用策略- 将来新增"新计算规则",只要新增一个策略类即可
6. 优缺点
6.1 优点
- 消除大量 if/else(条件分支被策略类替代)
- 算法可扩展:新增策略不必大改原代码
- 复用性强:策略实现可以在多个上下文中使用
- 更符合开闭原则:对扩展开放,对修改关闭
6.2 缺点
- 策略类增多:可能导致类数量上升
- 客户端/工厂需要维护"策略选择逻辑"(如果选择逻辑仍写一堆 if,可能又回来了)
- 如果策略之间共享复杂公共逻辑,可能需要进一步抽象(或结合模板方法/组合等)
7. 和其他模式怎么区分?
7.1 策略 vs 简单工厂/工厂方法
- 策略:解决"算法/规则如何替换"
- 工厂:解决"对象如何创建(选择具体策略类)"
实际项目里经常组合使用:工厂负责创建对应策略,策略负责算法本体。
7.2 策略 vs 模板方法
- 模板方法:把"流程骨架"固定,把某些步骤延迟到子类实现
- 策略:把"某个可变点"直接封装为独立算法,运行时可切换
7.3 策略 vs 状态模式
- 状态模式 :对象在不同状态下行为不同,且状态通常会在运行过程中自动切换
- 策略模式:通常由外部决定当前使用哪种策略(策略本身不一定管理"状态流转")
8. 适用场景
满足以下情况时,策略模式很合适:
- 系统需要在多种算法/规则之间切换
- 算法实现彼此差异较大,但对外暴露统一接口
- 频繁出现"if/else 根据条件选择不同处理"
- 希望将算法从业务流程中解耦,便于扩展与测试
9. 总结
策略模式通过"抽象策略 + 多个具体策略 + 上下文持有策略引用",把可变算法/规则从调用方逻辑中解耦出来。客户端只需选择合适的策略即可完成行为替换,从而减少分支代码、提高扩展性。
