
在软件开发中,我们常常会遇到这样的场景:同一个功能需要根据不同的条件选择不同的算法或行为。例如:
如果直接在代码中通过大量的 if-else 或 switch-case 实现这些分支逻辑,会导致代码臃肿、难以维护,且新增或修改算法时需要频繁修改原有代码,违反开闭原则(对扩展开放,对修改关闭)。
策略模式正是为了解决这类问题而诞生。它通过将算法抽象为独立的“策略”对象,使得算法可以灵活替换,系统更易扩展。接下来,我们从一个实际案例出发,一步步拆解策略模式的原理和实现。
策略模式(Strategy Pattern) 是一种行为型设计模式,允许你定义一系列算法(策略),并将每个算法封装成独立的类,使得它们可以相互替换。策略模式让算法的变化独立于使用它的客户端。
类比理解: 想象你有一个导航APP,可以根据不同策略(最快路线、最短路线、避开收费)规划路线。策略模式就像让你在APP运行时自由切换这些路线策略,而无需重写整个导航系统。
假设你要实现一个支付系统,支持支付宝、微信、信用卡支付。如果直接编码,可能会写出这样的代码:
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 难以维护。if-else 分支。策略模式包含三个核心角色:

话不多说直接上代码
开发智能客服系统,需根据业务场景调用不同AI服务:
要求:通过配置切换AI服务,核心业务代码无需修改。
/**
* AI服务策略接口(所有AI服务的共同契约)
*/
public interface AIService {
String executeTask(String input); // 执行AI任务
String getProviderName(); // 返回服务商名称
}策略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";
}
}/**
* 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("用户咨询订单"));
}
}AB测试:同时使用多个AI服务生成结果,对比质量
AIService serviceA = new OpenAIService("sk-xxx");
AIService serviceB = new QianfanService("token-xxx");
String resultA = serviceA.executeTask(input);
String resultB = serviceB.executeTask(input);故障转移:当主服务不可用时自动切换备用服务
try {
return mainService.executeTask(input);
} catch (ServiceException e) {
log.warn("主服务不可用,切换备用");
return backupService.executeTask(input);
}