策略模式(Strategy Pattern)是一种行为型设计模式,它定义了一系列算法,将每个算法封装起来并使它们可以相互替换。策略模式让算法的变化独立于使用算法的客户端,从而实现灵活的算法切换。

简单来说,策略模式就像 “出行方式选择”—— 去同一个目的地可以选择步行、骑车、开车等不同策略,这些策略(算法)可根据情况随时切换,而不影响出行的目标。

策略模式的UML类图如下:

image.png

上图中:

  • 策略接口(Strategy):定义所有具体策略必须实现的方法(如execute()),统一算法的调用方式。
  • 具体策略(ConcreteStrategyA/B/C):实现策略接口,包含具体的算法逻辑(如不同的排序算法、支付方式)。
  • 环境类(Context):持有一个策略对象的引用,提供setStrategy()方法动态切换策略,通过doOperation()方法调用当前策略的算法。

策略模式的核心价值是算法的封装与切换,它将算法的定义与使用分离,使得:

  1. 可以在不修改客户端的情况下新增算法(符合开闭原则)
  2. 可以在运行时动态切换算法
  3. 避免使用多重条件判断(if-else/switch)

常见应用场景:支付方式选择(微信、支付宝、银行卡)、排序算法切换、折扣计算策略等。

下面以 “电商平台的折扣计算” 为例,展示策略模式的实现。不同用户(普通用户、会员、VIP)有不同的折扣策略,且折扣规则可能随时调整,使用策略模式可以灵活切换和扩展这些折扣算法。

首先,定义一个统一的折扣策略抽象接口

1
2
3
4
5
// 策略接口:定义折扣计算的统一方法
interface DiscountStrategy {
// 计算折扣后价格
double calculate(double originalPrice);
}

然后定义针对不同用户的折扣策略

1
2
3
4
5
6
7
8
// 具体策略1:普通用户(无折扣)
class NormalUserDiscount implements DiscountStrategy {
@Override
public double calculate(double originalPrice) {
System.out.println("普通用户:无折扣");
return originalPrice;
}
}
1
2
3
4
5
6
7
8
9
// 具体策略2:会员用户(9折)
class MemberDiscount implements DiscountStrategy {
@Override
public double calculate(double originalPrice) {
double discountedPrice = originalPrice * 0.9;
System.out.println("会员用户:9折,折后价:" + discountedPrice);
return discountedPrice;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
// 具体策略3:VIP用户(8折+满100减20)
class VipDiscount implements DiscountStrategy {
@Override
public double calculate(double originalPrice) {
double tempPrice = originalPrice * 0.8;
// 满100再减20
if (tempPrice >= 100) {
tempPrice -= 20;
}
System.out.println("VIP用户:8折+满100减20,折后价:" + tempPrice);
return tempPrice;
}
}

第三步,定义一个使用策略的上下文,它持有策略对象,能够根据不同策略计算折扣

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 环境类:订单上下文(使用折扣策略)
class OrderContext {
// 持有当前折扣策略
private DiscountStrategy discountStrategy;

// 构造时指定初始策略
public OrderContext(DiscountStrategy discountStrategy) {
this.discountStrategy = discountStrategy;
}

// 动态切换策略
public void setDiscountStrategy(DiscountStrategy discountStrategy) {
this.discountStrategy = discountStrategy;
}

// 计算最终价格(委托给当前策略)
public double calculateFinalPrice(double originalPrice) {
return discountStrategy.calculate(originalPrice);
}
}

下面的代码演示了客户端调用折扣策略的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 客户端:模拟订单结算
public class ShoppingCart {
public static void main(String[] args) {
double goodsPrice = 150.0; // 商品原价

// 1. 普通用户下单
OrderContext order = new OrderContext(new NormalUserDiscount());
order.calculateFinalPrice(goodsPrice);

// 2. 切换为会员用户
order.setDiscountStrategy(new MemberDiscount());
order.calculateFinalPrice(goodsPrice);

// 3. 切换为VIP用户
order.setDiscountStrategy(new VipDiscount());
order.calculateFinalPrice(goodsPrice);

// 4. 新增策略:节日促销(7折)无需修改原有代码
order.setDiscountStrategy(new HolidayDiscount());
order.calculateFinalPrice(goodsPrice);
}
}

有了策略模式,那么我们就可以根据需求增加不同的策略,比如针对某个促销定义一个新的策略,我们只需要增加一个策略对象即可

1
2
3
4
5
6
7
8
9
// 新增策略:节日促销(7折)- 体现扩展性
class HolidayDiscount implements DiscountStrategy {
@Override
public double calculate(double originalPrice) {
double discountedPrice = originalPrice * 0.7;
System.out.println("节日促销:7折,折后价:" + discountedPrice);
return discountedPrice;
}
}

使用策略模式的优势如下:

  • 消除条件判断:避免使用if-elseswitch判断用户类型来选择折扣(传统方式会导致代码臃肿且难维护)。
  • 动态切换:支持运行时根据情况切换策略(如用户升级为 VIP 后立即应用 VIP 折扣)。
  • 易于扩展:比如上面的代码中,新增折扣策略只需实现DiscountStrategy接口,无需修改现有代码(符合开闭原则)。
  • 算法复用:不同订单可以共享同一个策略实例(如所有会员都使用MemberDiscount)。