重生之设计模式:策略模式

Handsome
2025-03-13
点 赞
0
热 度
63
评 论
1

前言

在软件开发中,我们常常会遇到这样的场景:​同一个功能需要根据不同的条件选择不同的算法或行为。例如:

  • 电商系统的促销活动(满减、折扣、积分抵扣等),不同活动对应不同的计算规则。

  • 导航系统根据实时路况选择不同的路径策略(最短距离、最快速度、避开拥堵)。

  • 支付系统支持多种支付方式(支付宝、微信、信用卡),每种方式有不同的处理逻辑。

  • 最近开发遇到多平台AI不同处理逻辑也是通过策略模式+工厂方法来开发的

如果直接在代码中通过大量的 if-elseswitch-case 实现这些分支逻辑,会导致代码臃肿、难以维护,且新增或修改算法时需要频繁修改原有代码,违反开闭原则​(对扩展开放,对修改关闭)。

策略模式正是为了解决这类问题而诞生。它通过将算法抽象为独立的“策略”对象,使得算法可以灵活替换,系统更易扩展。接下来,我们从一个实际案例出发,一步步拆解策略模式的原理和实现。

0be613b6-4693-44a6-b287-bd98facfe267.jpeg


策略模式从0开始教程

​一、什么是策略模式?

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

类比理解
想象你有一个导航APP,可以根据不同策略(最快路线、最短路线、避开收费)规划路线。策略模式就像让你在APP运行时自由切换这些路线策略,而无需重写整个导航系统。


​二、为什么需要策略模式?

​1. 直接编码的问题

假设你要实现一个支付系统,支持支付宝、微信、信用卡支付。如果直接编码,可能会写出这样的代码:

public class PaymentService {
    public void pay(String paymentType, double amount) {
        if ("alipay".equals(paymentType)) {
            // 支付宝支付逻辑
        } else if ("wechat".equals(paymentType)) {
            // 微信支付逻辑
        } else if ("creditCard".equals(paymentType)) {
            // 信用卡支付逻辑
        }
    }
}

问题

  • 违反开闭原则:新增支付方式需修改原有代码。

  • 代码臃肿:大量 if-else 难以维护。

  • 复用性差:算法逻辑与业务耦合,无法复用。

​2. 策略模式的优势

  • 解耦:将算法逻辑与业务代码分离。

  • 灵活扩展:新增策略无需修改已有代码。

  • 消除条件判断:避免复杂的 if-else 分支。

策略模式的结构

策略模式包含三个核心角色:


策略模式实战:多AI服务动态调用

话不多说直接上代码

272ecf37-71eb-4d2d-93c3-747335723dc8.gif

一、场景需求

开发智能客服系统,需根据业务场景调用不同AI服务:

  1. OpenAI:生成创意文案

  2. 百度千帆:处理商品推荐

  3. 智谱AI:回答售后问题

  4. DeepSeek:分析用户行为

要求:通过配置切换AI服务,核心业务代码无需修改。


​二、策略模式实现

​1. 定义策略接口

/**
 * AI服务策略接口(所有AI服务的共同契约)
 */
public interface AIService {
    String executeTask(String input);  // 执行AI任务
    String getProviderName();          // 返回服务商名称
}

​2. 实现具体策略

策略1:OpenAI服务

public class OpenAIService implements AIService {
    private final String apiKey;

    public OpenAIService(String apiKey) {
        this.apiKey = apiKey;
    }

    @Override
    public String executeTask(String input) {
        // 实际调用OpenAI API(此处模拟实现)
        return "[OpenAI] 生成文案:" + input.toUpperCase() + "!";
    }

    @Override
    public String getProviderName() {
        return "OPENAI";
    }
}

策略2:千帆商品推荐

public class QianfanService implements AIService {
    private final String accessToken;

    public QianfanService(String accessToken) {
        this.accessToken = accessToken;
    }

    @Override
    public String executeTask(String input) {
        // 调用千帆推荐API
        return "[千帆] 推荐商品:手机、耳机,基于输入:" + input;
    }

    @Override
    public String getProviderName() {
        return "QIANFAN";
    }
}

策略3:智谱客服问答

public class ZhipuService implements AIService {
    private final String secretKey;

    public ZhipuService(String secretKey) {
        this.secretKey = secretKey;
    }

    @Override
    public String executeTask(String input) {
        // 调用智谱问答API
        return "[智谱] 您的问题'" + input + "'的答案是:商品已发货";
    }

    @Override
    public String getProviderName() {
        return "ZHIPU";
    }
}

​3. 上下文控制类

/**
 * AI服务执行上下文
 */
public class AIServiceContext {
    private AIService strategy;

    // 动态注入策略
    public void setStrategy(AIService strategy) {
        this.strategy = strategy;
        System.out.println("已切换至AI服务:" + strategy.getProviderName());
    }

    // 执行AI任务
    public String processInput(String input) {
        if (strategy == null) {
            throw new IllegalStateException("未选择AI服务策略");
        }
        return strategy.executeTask(input);
    }
}

​三、客户端动态调用

public class Client {
    public static void main(String[] args) {
        AIServiceContext context = new AIServiceContext();
        
        // 创建策略对象
        AIService openAI = new OpenAIService("sk-xxx");
        AIService qianfan = new QianfanService("token-xxx");
        
        // 动态切换策略
        context.setStrategy(openAI);
        System.out.println(context.processInput("夏季促销")); 

        context.setStrategy(qianfan);
        System.out.println(context.processInput("用户喜欢电子产品"));
    }
}

输出结果

已切换至AI服务:OPENAI
[OpenAI] 生成文案:夏季促销!

已切换至AI服务:QIANFAN  
[千帆] 推荐商品:手机、耳机,基于输入:用户喜欢电子产品

​四、工厂模式扩展(配置化)​

/**
 * AI服务工厂(根据配置创建策略)
 */
public class AIServiceFactory {
    public static AIService createService(String config) {
        // 解析配置(示例格式:PROVIDER:KEY)
        String[] parts = config.split(":");
        String provider = parts[0];
        String authKey = parts[1];

        switch (provider.toUpperCase()) {
            case "OPENAI":
                return new OpenAIService(authKey);
            case "QIANFAN":
                return new QianfanService(authKey);
            case "ZHIPU":
                return new ZhipuService(authKey);
            default:
                throw new IllegalArgumentException("不支持的AI服务: " + provider);
        }
    }
}

// 配置文件 application.conf
ai.config=QIANFAN:token-xxx
// 配置化调用示例
public class ConfigClient {
    public static void main(String[] args) {
        // 从配置文件读取配置
        String config = "QIANFAN:token-xxx"; 
        
        AIService service = AIServiceFactory.createService(config);
        AIServiceContext context = new AIServiceContext();
        context.setStrategy(service);
        
        System.out.println(context.processInput("用户咨询订单"));
    }
}

​五、实际应用场景

  1. AB测试:同时使用多个AI服务生成结果,对比质量

    AIService serviceA = new OpenAIService("sk-xxx");
    AIService serviceB = new QianfanService("token-xxx");
    String resultA = serviceA.executeTask(input);
    String resultB = serviceB.executeTask(input);
  2. 故障转移:当主服务不可用时自动切换备用服务

    try {
        return mainService.executeTask(input);
    } catch (ServiceException e) {
        log.warn("主服务不可用,切换备用");
        return backupService.executeTask(input);
    }

策略模式的优缺点

​优点

  1. 符合开闭原则:新增策略无需修改已有代码。

  2. 避免多重条件判断

  3. 提高代码复用性:策略可被多个客户端共享。

​缺点

  1. 客户端必须知晓所有策略:需理解不同策略的区别。

  2. 类数量增加:每个策略一个类,可能增加系统复杂度。

适用场景

  1. 系统需要多种算法变体(例如排序、支付、压缩算法)。

  2. 需要在运行时动态切换算法。

  3. 需要将算法细节与业务逻辑解耦。

a45133b9-7567-4383-b1e7-bc0efaa0af16.jpeg


心若有所向往,何惧道阻且长

Handsome

infp 调停者

站长

具有版权性

请您在转载、复制时注明本文 作者、链接及内容来源信息。 若涉及转载第三方内容,还需一同注明。

具有时效性

目录

欢迎来到Handsome的站点,为您导航全站动态

17 文章数
4 分类数
21 评论数
17标签数

访问统计