0%

策略模式

策略模式(Strategy Pattern):算法的封装与灵活切换

策略模式是行为型设计模式的一种,核心思想是定义一系列算法,将每个算法封装成独立的策略类,使它们可以相互替换,从而让算法的变化独立于使用算法的客户端。这种模式就像 “出行方式的选择”—— 无论是步行、骑车还是开车,目的都是到达目的地,只是方式不同,客户端可根据需求灵活切换。

策略模式的核心结构

策略模式通过三个核心角色实现算法的封装与切换,结构清晰且职责分明:

策略接口(Strategy)

  • 定义所有算法的公共接口,声明算法的核心方法(如计算、执行等)。
  • 示例:PaymentStrategy(支付策略接口,定义pay(double amount)方法)。

具体策略(ConcreteStrategy)

  • 实现策略接口,封装具体的算法逻辑,是策略模式的 “可替换单元”。
  • 示例:AlipayStrategy(支付宝支付)、WechatPayStrategy(微信支付)。

上下文(Context)

  • 使用策略的客户端角色,持有策略接口的引用,负责将具体策略传递给客户端,或根据场景选择策略。
  • 上下文不直接实现算法,而是委托给具体策略执行,自身仅关注 “何时使用算法” 而非 “如何实现算法”。
  • 示例:Order(订单上下文,通过支付策略完成支付)。

代码实现示例

以 “订单支付系统” 为例,展示策略模式的应用:订单可通过支付宝、微信等不同方式支付,客户端可动态选择支付方式。

1. 策略接口(Strategy)

1
2
3
4
5
// 策略接口:支付策略
public interface PaymentStrategy {
// 支付方法(核心算法)
void pay(double amount);
}

2. 具体策略(ConcreteStrategy)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 具体策略1:支付宝支付
public class AlipayStrategy implements PaymentStrategy {
private String account; // 支付宝账号

public AlipayStrategy(String account) {
this.account = account;
}

@Override
public void pay(double amount) {
System.out.printf("使用支付宝账号【%s】支付了%.2f元%n", account, amount);
}
}

// 具体策略2:微信支付
public class WechatPayStrategy implements PaymentStrategy {
private String openId; // 微信OpenID

public WechatPayStrategy(String openId) {
this.openId = openId;
}

@Override
public void pay(double amount) {
System.out.printf("使用微信OpenID【%s】支付了%.2f元%n", openId, amount);
}
}

3. 上下文(Context)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 上下文:订单
public class Order {
private double amount; // 订单金额
private PaymentStrategy paymentStrategy; // 持有支付策略引用

public Order(double amount) {
this.amount = amount;
}

// 设置支付策略(动态切换)
public void setPaymentStrategy(PaymentStrategy strategy) {
this.paymentStrategy = strategy;
}

// 执行支付(委托给策略)
public void pay() {
if (paymentStrategy == null) {
throw new IllegalStateException("请选择支付方式");
}
paymentStrategy.pay(amount); // 调用具体策略的算法
}
}

4. 客户端使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class StrategyDemo {
public static void main(String[] args) {
// 创建订单(上下文)
Order order = new Order(199.99);

// 选择支付宝支付(策略1)
order.setPaymentStrategy(new AlipayStrategy("user@alipay.com"));
order.pay(); // 输出:使用支付宝账号【user@alipay.com】支付了199.99元

// 切换为微信支付(策略2)
order.setPaymentStrategy(new WechatPayStrategy("o6_bmjrPTlm6_2sgVt7hMZOPfL2M"));
order.pay(); // 输出:使用微信OpenID【o6_bmjrPTlm6_2sgVt7hMZOPfL2M】支付了199.99元
}
}

策略模式的核心优势

  1. 算法的灵活切换
    客户端可在运行时动态更换策略(如订单支付时从支付宝切换到微信),无需修改上下文或其他策略的代码,符合开闭原则。
  2. 算法的封装与隔离
    每个算法被封装在独立的策略类中,避免了算法逻辑与客户端代码的混杂(如消除大量if-else判断),提高代码可读性和可维护性。
  3. 易于扩展新算法
    新增算法时,只需实现策略接口并添加具体策略类,无需修改现有代码(如新增 “银行卡支付” 只需添加BankCardStrategy)。
  4. 单一职责原则
    每个策略类仅负责实现一种算法,上下文仅负责协调策略的使用,职责清晰,降低耦合度。

适用场景

  1. 存在多种可替换的算法
    当系统中某个功能有多种实现方式(如排序算法、支付方式、日志记录方式),且需要根据场景动态选择时。
  2. 避免冗长的条件判断
    若代码中存在大量if-elseswitch语句用于选择不同算法(如if (type == "ALIPAY") { ... } else if (type == "WECHAT") { ... }),策略模式可将这些判断逻辑转移为策略的动态切换。
  3. 算法需要独立扩展
    算法的变化不应影响客户端或其他算法(如新增支付方式不应修改订单类)。
  4. 客户端需要知道所有策略
    客户端需了解不同策略的差异,以便选择合适的策略(如用户需手动选择支付方式)。

优缺点分析

优点

  • 灵活性高:策略可动态切换,适应不同场景需求。
  • 可维护性强:算法封装在独立类中,便于修改和测试。
  • 可扩展性好:新增策略无需修改现有代码,符合开闭原则。

缺点

  • 客户端需了解策略:客户端必须知道所有策略的存在及差异,才能选择合适的策略(增加了客户端的使用成本)。
  • 策略类数量膨胀:若算法过多,会导致策略类数量激增(可通过结合工厂模式缓解)。

经典应用案例

  1. Java 集合框架的排序
    Collections.sort()方法接收Comparator接口(策略接口),客户端可通过实现Comparator定义不同的排序策略(如按名称排序、按年龄排序)。
  2. Spring 的资源访问
    Spring 的Resource接口(策略接口)定义了资源访问的方法,具体策略如FileSystemResource(文件系统资源)、ClassPathResource(类路径资源),可根据资源位置动态选择。
  3. 日志框架的输出策略
    日志框架(如 Logback)中,日志可输出到控制台、文件或数据库,每种输出方式对应一个策略类,可通过配置动态切换。
  4. 电商系统的促销策略
    订单结算时可应用不同的促销策略(满减、折扣、优惠券),每种策略对应一个具体策略类,上下文根据订单金额或用户等级选择策略。

总结

策略模式通过 “定义策略接口、封装具体算法、上下文协调使用” 的方式,实现了算法的灵活切换与扩展。其核心价值在于分离算法的定义与使用,消除条件判断语句,使系统更易于维护和扩展。在实际开发中,策略模式常与工厂模式结合使用(由工厂负责创建策略),以降低客户端对策略的直接依赖

欢迎关注我的其它发布渠道