首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >设计模式讲解03—策略模式(Strategy)

设计模式讲解03—策略模式(Strategy)

作者头像
CodeSuc
发布2025-11-03 18:00:46
发布2025-11-03 18:00:46
1300
举报

1. 概述

定义:策略模式(Strategy Pattern)是一种行为型模式。在这个模式中,会定义一组算法类,将每个算法实现分别封装起来,让它们可以互相替换

解释:在策略模式定义了一系列算法或策略,并将每个算法封装在独立的类中,使得它们可以互相替换。通过使用策略模式,可以在运行时根据需要选择不同的算法,而不需要修改客户端代码。在策略模式中,我们创建表示各种策略对象和一个行为随着策略对象的改变而改变的 context 对象。不同的策略对象决定不同的 context 对象的执行算法。

2. 简单介绍

策略模式主要用于解决

  • 在多种相似算法存在时,当使用条件语句(如 if ... else ...)导致的复杂性和难以维护的问题

使用场景:

  • 当一个系统中有多个类,这些类之间的区别仅在于它们的实现行为

实现方式:

  • 定义策略接口:所有策略类都将实现这个统一的接口
  • 创建具体策略实现类:每个策略类封装一个不同且具体的算法或行为
  • 上下文类:包含一个策略对象的引用,可以通过该引用调用不同的策略

常见应用场景:

  1. 第三方支付对接:定义一个用于支付的策略接口。不同的支付方式(如:微信支付、支付宝支付)实现不同的策略类,通过一个上下文对象来根据具体的实现调用对应的支付行为
  2. 等等 ......

3. 优缺点

优点:

  1. 算法切换自由:可以在运行时根据需要切换具体实现算法
  2. 避免多重条件判断:消除了复杂的条件语句
  3. 扩展性好:新增算法只需新增一个策略类,无需修改现有代码

缺点:

  1. 策略类数量增多:每增加一个算法,就需要增加一个策略类
  2. 所有策略类都需要暴露:策略类需要对外公开,以便可以被选择和使用

使用建议:

  • 当系统中有多种算法或行为,且它们之间可以相互替换时,使用策略模式
  • 当系统需要动态选择算法时,策略模式是一个合适的选择
  • 如果系统中策略类数量过多,考虑使用其他模式或设计技巧来解决类膨胀问题

4. 结构

策略模式包含以下几个主要角色:

  • 环境(Context):维护一个对策略对象的引用,负责将客户端请求委派给具体的策略对象执行。环境类可以通过依赖注入、简单工厂等方式来获取具体策略对象
  • 抽象策略(Abstract Strategy):定义了策略对象的公共接口或抽象类,规定了具体策略类必须实现的方法
  • 具体策略(Concrete Strategy):实现了抽象策略定义的接口或抽象类,包含了具体的算法实现

5. 代码实现

5.1. 示例 Demo
a. 需求介绍

我们将创建一个定义活动的 Strategy 接口和实现了 Strategy 接口的实体策略类。Context 是一个使用了某种策略的类

我们在 main 方法中使用 Context 上下文对象和策略对象来演示 Context 在它所配置或使用的策略发送改变时的行为变化

b. 代码演示
  1. 创建策略接口,指定策略实现类具有的方法
代码语言:javascript
复制
/**
 * @Description 策略接口
 * @Author Mr.Zhang
 * @Date 2025/5/6 0:36
 * @Version 1.0
 */
public interface Strategy {
    // 具体的操作由策略类实现
    int doOperation(int num1, int num2);
}
  1. 创建三个具体的策略接口实现类,分别对应加法、减法、乘法操作
代码语言:javascript
复制
/**
 * @Description 加法操作
 * @Author Mr.Zhang
 * @Date 2025/5/6 0:38
 * @Version 1.0
 */
public class OperationAdd implements Strategy {

    public int doOperation(int num1, int num2) {
        return num1 + num2;
    }
}
代码语言:javascript
复制
/**
 * @Description 减法操作
 * @Author Mr.Zhang
 * @Date 2025/5/6 0:38
 * @Version 1.0
 */
public class OperationSubtract implements Strategy {
    public int doOperation(int num1, int num2) {
        return num1 - num2;
    }
}
代码语言:javascript
复制
/**
 * @Description 乘法操作
 * @Author Mr.Zhang
 * @Date 2025/5/6 0:38
 * @Version 1.0
 */
public class OperationMultiply implements Strategy {

    public int doOperation(int num1, int num2) {
        return num1 * num2;
    }
}
  1. 创建 Context 上下文对象,维护对策略对象的引用
代码语言:javascript
复制
/**
 * @Description 工厂类,用来创建策略对象
 * @Author Mr.Zhang
 * @Date 2025/5/7 21:34
 * @Version 1.0
 */
public class StrategyFactory {

    private Strategy strategy;

    public StrategyFactory(Strategy strategy) {
        this.strategy = strategy;
    }

    public int execute(int num1, int num2) {
        return strategy.doOperation(num1, num2);
    }
}
  1. 编写测试代码,测试
代码语言:javascript
复制
/**
 * @Description TODO
 * @Author Mr.Zhang
 * @Date 2025/5/7 21:37
 * @Version 1.0
 */
public class Main {
    public static void main(String[] args) {
        StrategyFactory factory = new StrategyFactory(new OperationAdd());
        System.out.println("10 + 5 = " + factory.execute(10, 5));

        factory = new StrategyFactory(new OperationSubtract());
        System.out.println("10 - 5 = " + factory.execute(10, 5));

        factory = new StrategyFactory(new OperationMultiply());
        System.out.println("10 * 5 = " + factory.execute(10, 5));
    }
}

输出

代码语言:javascript
复制
10 + 5 = 15
10 - 5 = 5
10 * 5 = 50

至此,我们已经学会了策略模式的使用。那下面我将再举一个我实际开发中用到的在对接第三方支付时使用到的策略模式的例子

5.2. 应用场景

假设我们要做一个多支付方式扣款的功能,需求如下:

  1. 设置多个支付方式,包含微信,支付宝,银联
  2. 其中微信优惠0.5元.支付宝优惠0.7元,银联优惠1元.
  3. 如果使用微信支付订单满30元优惠0.5元 满50元优惠1元
  4. 支付宝支付订单满40优惠 0.7元,满80元优惠2元

针对这个需求,如果我们直接使用 if...else... 来实现的话无论是可读性还是可维护性都特别低,复杂度较高。那我们完全可以采用 策略模式 + 工厂模式 来进行优化

  1. 定义支付策略接口(抽象出策略类所共有的支付方法)
代码语言:javascript
复制
/**
 * @author  ZGM
 * 支付策略接口
 */
public interface PayStrategy {
    /**
     * 优惠后支付金额
     */
    long discountPayMoney(Long money, Integer plat);

}
  1. 为不同的支付方式创建不同的策略实现类
代码语言:javascript
复制
/**
 * 微信支付
 */
@Slf4j
@Component("weChatPay")
public class WeChatPayStrategy implements PayStrategy {
    /**
     * 优惠后支付金额
     * @param money
     * @param plat
     */
    @Override
    public long discountPayMoney(Long money, Integer plat) {
	   	long price=money;
       	 price-=50;
            if(订单金额>=50元){
                price-=100;
            }else if(订单金额>=30元){
                price-=50;
            }
        return price;
    }
}
代码语言:javascript
复制
/**
 * 银联支付
 */
@Slf4j
@Component("unionpayPay")
public class UnionpayPayStrategy implements PayStrategy {
    /**
     * 优惠后支付金额
     *
     * @param money
     * @param plat
     */
    @Override
    public long discountPayMoney(Long money, Integer plat) {
    	long price=money;
        price-=100;


        return price;
    }
}
代码语言:javascript
复制
/**
 * 支付宝支付
 */
@Slf4j
@Component("alipayPay")
public class AlipayPayStrategy implements PayStrategy {

    /**
     * 优惠后支付金额
     *
     * @param money
     * @param plat
     */
    @Override
    public long discountPayMoney(Long money, Integer plat) {
    	 long plat=money;
         price-=70;
         if(订单金额大于>=80元){
            price-=200;
         }else if(订单金额>=40){
            price-=70;
         }
        return price;
    }
}
  1. 紧接着,创建一个上下文对象,用来指定具体执行的类
代码语言:javascript
复制
/**
*工厂类
*/
@Service
@Slf4j
public class PayFactory {
    @Autowired
   Map<String, PayStrategy > map = new ConcurrentHashMap<>();

    @PostConstruct
    public void init() {
        // 在此处将策略类的实例添加到 map 中
        map.put("alipay", new AliPayStrategy());
        map.put("wechatpay", new WeChatPayStrategy());
        // ...
    }

	
    public PayStrategy getStrategy(String componentName) {
        PayStrategy strategy= map.get(componentName);
        if (strategy == null) {
            log.error("没有获取工厂类 componentName={}", componentName);
            return null;
        }
        return strategy;
    }
}
  1. 编写测试代码
代码语言:javascript
复制
@RestController
public class TestController {
    @Autowired
    PayFactory payFactory;

    @RequestMapping(value = "test")
    public Long test(Integer plat) {
//        plat==0 微信 ,1银联,2支付宝
//        因为策略类组件名不能重复所以我们最好是做一个常量池来进行类型转换.这里就不一一去写了.
        PayStrategy alipayPay = payFactory.getStrategy("alipayPay");
        Long price = alipayPay.discountPayMoney(10000L);
        return price;
    }
}

输出

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-06-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 概述
  • 2. 简单介绍
  • 3. 优缺点
  • 4. 结构
  • 5. 代码实现
    • 5.1. 示例 Demo
      • a. 需求介绍
      • b. 代码演示
    • 5.2. 应用场景
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档