目录

设计模式策略模式以及基于Spring依赖注入的策略模式的应用

设计模式——策略模式以及基于Spring依赖注入的策略模式的应用

好的,策略模式(Strategy Pattern)是一种行为型设计模式, 用于定义一系列算法,并将每个算法封装成独立的类,使得它们可以相互替换 。策略模式的核心思想是 将算法与使用算法的客户端解耦 ,让算法的变化独立于客户端的使用。

1.策略模式的核心概念

  • 策略接口(Strategy Interface)

    定义所有支持的算法的公共接口,所有具体策略类必须实现该接口。

  • 具体策略类(Concrete Strategies)

    实现策略接口的具体算法。

  • 上下文类(Context Class)

    持有一个策略接口的引用,并通过该接口调用具体策略的算法。

2. 为什么需要策略模式?

  • 避免冗长的条件判断当代码中存在大量 if-elseswitch-case 来根据条件选择不同算法时,策略模式可以消除这些重复判断
  • 开闭原则(OCP) :新增算法时无需修改现有代码,只需添加新的策略类。
  • 解耦 :将算法逻辑与业务逻辑分离,便于维护和扩展。

3. 策略模式的实现步骤

3. 1. 定义策略接口

// 策略接口:定义算法的抽象
public interface PaymentStrategy {
    void pay(double amount);
}

3.2. 实现具体策略类

// 具体策略:支付宝支付
public class AlipayStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("使用支付宝支付:" + amount + "元");
    }
}

// 具体策略:微信支付
public class WechatPayStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("使用微信支付:" + amount + "元");
    }
}

3.3 定义上下文类(持有策略的选择)

// 上下文类:负责调用策略
public class PaymentContext {
    private PaymentStrategy strategy;

    // 设置策略(通过构造器或Setter注入)
    public PaymentContext(PaymentStrategy strategy) {
        this.strategy = strategy;
    }

    // 执行支付
    public void executePayment(double amount) {
        strategy.pay(amount);
    }

    // 动态切换策略(可选)
    public void setStrategy(PaymentStrategy strategy) {
        this.strategy = strategy;
    }
}

3.4. 客户端调用

public class Client {
    public static void main(String[] args) {
        // 选择支付宝策略
        PaymentContext context = new PaymentContext(new AlipayStrategy());
        context.executePayment(100.0);  // 输出:使用支付宝支付:100.0元

        // 动态切换为微信支付
        context.setStrategy(new WechatPayStrategy());
        context.executePayment(200.0);  // 输出:使用微信支付:200.0元
    }
}

4.策略模式的优点

  1. 灵活切换算法 :通过替换策略对象,可以动态改变程序的行为。
  2. 符合开闭原则 :新增算法无需修改已有代码。
  3. 消除重复代码 :避免多层条件分支的臃肿逻辑。
  4. 高内聚低耦合 :每个策略类独立负责自己的算法逻辑。

5.策略模式的典型应用场景

  1. 支付方式选择 :支付宝、微信、信用卡等支付方式的切换。
  2. 排序算法选择 :根据数据规模选择快速排序、归并排序等。
  3. 折扣策略 :满减、打折、积分抵扣等促销活动。
  4. 游戏中的角色行为 :不同武器攻击方式、不同移动策略(行走、飞行)。

6. 策略模式与Spring框架的结合

在Spring中,可以通过依赖注入(DI)动态管理策略实现类。例如:

// 1. 定义策略接口
public interface DiscountStrategy {
    double applyDiscount(double price);
}

// 2. 实现具体策略类
@Component("vipDiscount")  // Spring托管Bean
public class VipDiscountStrategy implements DiscountStrategy {
    @Override
    public double applyDiscount(double price) {
        return price * 0.8;  // VIP打8折
    }
}

@Component("holidayDiscount")
public class HolidayDiscountStrategy implements DiscountStrategy {
    @Override
    public double applyDiscount(double price) {
        return price * 0.9;  // 节假日打9折
    }
}

// 3. 上下文类(使用Spring注入策略)
@Service
public class DiscountContext {
    private final Map<String, DiscountStrategy> strategyMap;

    // 通过构造函数注入所有策略实现类(自动按Bean名称映射)
    public DiscountContext(Map<String, DiscountStrategy> strategyMap) {
        this.strategyMap = strategyMap;
    }

    public double executeDiscount(String strategyName, double price) {
        DiscountStrategy strategy = strategyMap.get(strategyName);
        if (strategy == null) {
            throw new IllegalArgumentException("策略不存在");
        }
        return strategy.applyDiscount(price);
    }
}

// 4. 客户端调用
@RestController
public class OrderController {
    @Autowired
    private DiscountContext discountContext;

    @PostMapping("/checkout")
    public double checkout(@RequestParam String discountType, @RequestParam double price) {
        return discountContext.executeDiscount(discountType, price);
    }
}

在上述的示例中,假期折扣和VIP折扣通过@Component注解均交予Spring容器管理,在DiscountContext中通过不同折扣类型的字符串切换,即可实现不同折扣算法的应用。这个实现相较之于前面的基础策略模式,可以看到在Context中,我们将存储Strategy的属性换成了Map,通过键值对配合Spring框架的依赖注入,实现了在调用者类(Controller)中策略的声明以及If-else的彻底清除(不用Map,那意味着需要在Context或者Controller中编写折扣策略的选择代码),降低代码的耦合度,同时也更为灵活地切换折扣算法。

7.策略模式的缺点

  • 类数量增多 :每个算法对应一个类,可能导致类膨胀。
  • 客户端需要了解策略差异 :客户端需要知道不同策略的适用场景。

8.总结

策略模式通过将算法封装成独立的类,实现了算法的灵活切换和业务逻辑的解耦。 当系统需要在运行时动态选择算法时,策略模式是理想的选择 。结合Spring等框架的依赖注入,可以更优雅地管理策略对象,提升代码的可维护性和扩展性。

9.参考

……