1.策略模式定义
策略模式(Strategy Pattern)是一种行为型设计模式,它定义了一组算法,将每个算法封装起来,并使它们可以相互替换,从而让算法的变化独立于使用它的客户(Client)。
换句话说, 策略模式让一个类的行为或其算法可以在运行时更改,而不会影响使用该类的代码。
UML图:
2.策略模式举例:
业务场景:需要实现一个商场收银系统,有三种策略,
- 正常结账
- 打折
- 满减
实现业务功能如下:
2.1 代码设计UML图如下:
2.2 关键代码:
CashContext代码:和抽象工厂结合,减少耦合。之前客户端需要了解CashContext和CashSuper两个类,现在只需要了解CashContext一个类,封装更好,耦合更小。
public class CashContext {
private CashSuper cs; //声明一个CashSuper对象
//通过构造方法,传入具体的收费策略
public CashContext(int cashType){
switch(cashType){
case 1:
this.cs = new CashNormal();
break;
case 2:
this.cs = new CashRebate(0.8d);
break;
case 3:
this.cs = new CashRebate(0.7d);
break;
case 4:
this.cs = new CashReturn(300d,100d);
break;
}
}
public double getResult(double price,int num){
//根据收费策略的不同,获得计算结果
return this.cs.acceptCash(price,num);
}
}
CashSuper:
public abstract class CashSuper {
public abstract double acceptCash(double price,int num);
}
CashReturn:
public class CashReturn extends CashSuper {
private double moneyCondition = 0d; //返利条件
private double moneyReturn = 0d; //返利值
//返利收费。初始化时需要输入返利条件和返利值。
//比如“满300返100”,就是moneyCondition=300,moneyReturn=100
public CashReturn(double moneyCondition,double moneyReturn){
this.moneyCondition = moneyCondition;
this.moneyReturn = moneyReturn;
}
//计算收费时,当达到返利条件,就原价减去返利值
public double acceptCash(double price,int num){
double result = price * num;
if (moneyCondition>0 && result >= moneyCondition)
result = result - Math.floor(result / moneyCondition) * moneyReturn;
return result;
}
}
客户端代码:
public class Test {
public static void main(String[] args){
System.out.println("**********************************************");
System.out.println("策略模式和简单工厂模式");
System.out.println();
int discount = 0; //商品折扣模式(1.正常收费 2.打八折 3.打七折)
double price = 0d; //商品单价
int num = 0; //商品购买数量
double totalPrices = 0d;//当前商品合计费用
double total = 0d; //总计所有商品费用
Scanner sc = new Scanner(System.in);
do {
System.out.println("请输入商品折扣模式(1.正常收费 2.打八折 3.打七折 4.满300送100):");
discount = Integer.parseInt(sc.nextLine());
System.out.println("请输入商品单价:");
price = Double.parseDouble(sc.nextLine());
System.out.println("请输入商品数量:");
num = Integer.parseInt(sc.nextLine());
System.out.println();
if (price>0 && num>0){
//根据用户输入,将对应的策略对象作为参数传入CashContext对象中
CashContext cc = new CashContext(discount);
//通过Context的getResult方法的调用,可以得到收取费用的结果
//让具体算法与客户进行了隔离
totalPrices = cc.getResult(price,num);
total = total + totalPrices;
System.out.println();
System.out.println("单价:"+ price + "元 数量:"+ num +" 合计:"+ totalPrices +"元");
System.out.println();
System.out.println("总计:"+ total+"元");
System.out.println();
}
}while(price>0 && num>0);
System.out.println();
System.out.println("**********************************************");
}
}
具体运行结果如下:
3.策略模式优缺点
✅ 优点
- 符合开闭原则(Open-Closed Principle):可以新增新的策略,而不影响已有代码。
- 避免冗长的 if-else 语句:如果不使用策略模式,可能会有大量 if-else 逻辑判断。
- 支持动态切换:可以在运行时自由更换不同的算法,而不修改原有代码。
- 代码更符合SOLID原则
设计原则 | 策略模式如何符合 |
---|---|
单一职责原则(SRP) | 每个 Strategy 只负责一个算法,职责清晰。 |
开闭原则(OCP) | 可以新增策略,而不修改原代码。 |
依赖倒置原则(DIP) | Context 依赖于 Strategy 接口,而不是具体实现。 |
❌ 缺点
- 增加了代码复杂度:每个策略都需要定义一个类,当策略过多时,会导致类爆炸。
- 客户端需要了解不同策略:调用方需要知道有哪些可用策略,才能正确选择。
4.策略模式的应用场景
✅ (1) 算法的可替换性
计算税收(不同国家税率)
支付方式(微信支付、支付宝、银行卡)
✅ (2) 处理不同格式的文件
解析 JSON、XML、CSV 文件时,使用不同的解析策略。
✅ (3) AI/机器学习中的优化策略
训练模型时,可以使用不同的优化算法(SGD、Adam、RMSprop)。
5.策略模式 vs 其他模式
设计模式 | 作用 | 适用场景 |
---|---|---|
策略模式 | 允许在运行时更换不同算法 | 当有多种算法可选,且希望避免 if-else 逻辑。 |
状态模式 | 允许对象在不同状态下表现出不同行为 | 对象的行为依赖于状态变化,例如订单状态。 |
工厂模式 | 负责创建对象,但不指定其具体实现 | 需要动态创建不同策略对象时,可结合策略模式使用。 |
6.总结
策略模式核心思想: 定义一组算法,让它们可以互相替换,而不会影响客户端代码。
适用于: 需要多个可替换算法,并希望避免 if-else 逻辑的场景。
优点: 符合开闭原则,可动态切换策略,避免冗长 if-else
缺点: 可能会增加类的数量,使代码更复杂。