Java设计模式-策略模式
模式概述
策略模式简介
核心思想:定义一系列算法(策略),将每个算法封装成独立的类,并使它们可以相互替换。策略模式让算法的变化独立于使用它的客户端,从而避免大量条件判断语句,提升代码的可维护性和扩展性。
模式类型:行为型设计模式(关注对象间的交互与职责分配)。
作用:
- 解耦策略定义与使用:策略的具体实现与调用逻辑分离,客户端只需关注策略接口;
- 消除条件语句:通过策略替换替代复杂的if-else或switch-case判断;
- 符合开闭原则:新增策略只需添加新策略类,无需修改现有代码;
- 提高复用性:策略类可被多个客户端共享使用。
典型应用场景:
- 支付方式选择(支付宝、微信、信用卡);
- 数据校验规则(手机号、邮箱、身份证号校验);
- 排序/加密算法切换(冒泡排序、快速排序、MD5、SHA-256);
- 促销活动折扣(满减、折扣券、会员专属价)。
我认为:策略模式是"算法的动态切换器",通过将每个算法封装成独立的"策略零件",让业务逻辑像"组装机器"一样灵活选择不同的"零件",彻底告别冗长的条件判断。
课程目标
- 理解策略模式的核心思想和经典应用场景
- 识别应用场景,使用策略模式解决功能要求
- 了解策略模式的优缺点
核心组件
角色-职责表
角色 | 职责 | 示例类名 |
---|---|---|
抽象策略(Strategy) | 定义所有具体策略的公共接口,声明策略需要实现的方法 | PaymentStrategy |
具体策略(Concrete Strategy) | 实现抽象策略接口,封装具体的算法逻辑 | AlipayStrategy 、WechatPayStrategy |
上下文(Context) | 持有策略接口引用,将客户端的请求委托给具体策略执行;提供策略切换方法 | OrderService |
类图
下面是一个简化的类图表示,展示了策略模式中的主要角色及其交互方式:
持有 实现 实现 实现 Context -PaymentStrategy strategy +setStrategy(PaymentStrategy strategy) +pay() <<interface>> PaymentStrategy +pay() AlipayStrategy +pay() WechatPayStrategy +pay() CreditCardStrategy +pay()
传统实现 VS 策略模式
案例需求
案例背景:电商系统中,订单支付支持支付宝、微信、信用卡三种方式。不同支付方式的支付逻辑不同(如签名验证、渠道调用),需要根据用户选择的支付方式执行对应逻辑。
传统实现(痛点版)
代码实现:
java
// 传统写法:上下文类直接包含策略判断逻辑
public class OrderService {
// 支付方式类型(假设用字符串标识)
private String paymentType;
public void setPaymentType(String paymentType) {
this.paymentType = paymentType;
}
public void pay() {
if ("ALIPAY".equals(paymentType)) {
// 支付宝支付逻辑:调用支付宝接口、生成签名、验证回调
System.out.println("调用支付宝支付接口,完成支付");
} else if ("WECHAT_PAY".equals(paymentType)) {
// 微信支付逻辑:调用微信支付API、生成二维码、处理异步通知
System.out.println("调用微信支付接口,生成支付二维码");
} else if ("CREDIT_CARD".equals(paymentType)) {
// 信用卡支付逻辑:验证卡号、有效期、CVV、调用银行接口
System.out.println("调用银行接口,验证信用卡信息并支付");
} else {
System.out.println("未支持的支付方式");
}
}
}
// 使用示例
public class Client {
public static void main(String[] args) {
OrderService orderService = new OrderService();
orderService.setPaymentType("ALIPAY");
orderService.pay(); // 输出:调用支付宝支付接口,完成支付
orderService.setPaymentType("WECHAT_PAY");
orderService.pay(); // 输出:调用微信支付接口,生成支付二维码
orderService.setPaymentType("CREDIT_CARD");
orderService.pay(); // 输出:调用银行接口,验证信用卡信息并支付
}
}
痛点总结:
- 条件判断冗余 :每新增一种支付方式,需在
pay()
方法中添加新的else if
分支,代码膨胀严重; - 可维护性差 :支付逻辑与订单服务强耦合,修改某支付方式需改动
OrderService
类; - 扩展性低:违反开闭原则,新增支付方式(如"云闪付")需修改现有代码;
- 复用性低:支付逻辑无法被其他业务(如退款、转账)复用。
策略模式 实现(优雅版)
代码实现:
java
// 1. 抽象策略接口:定义支付行为
interface PaymentStrategy {
void pay(); // 支付操作
}
// 2. 具体策略类:支付宝支付(独立封装)
class AlipayStrategy implements PaymentStrategy {
@Override
public void pay() {
System.out.println("调用支付宝支付接口,完成支付");
// 实际逻辑:生成签名、调用支付宝API、处理回调等(独立维护)
}
}
// 3. 具体策略类:微信支付(独立封装)
class WechatPayStrategy implements PaymentStrategy {
@Override
public void pay() {
System.out.println("调用微信支付接口,生成支付二维码");
// 实际逻辑:调用微信支付API、生成二维码、轮询回调等(独立维护)
}
}
// 4. 具体策略类:信用卡支付(独立封装)
class CreditCardStrategy implements PaymentStrategy {
@Override
public void pay() {
System.out.println("调用银行接口,验证信用卡信息并支付");
// 实际逻辑:验证卡号/CVV/有效期、调用银行支付接口等(独立维护)
}
}
// 5. 上下文类:订单服务(仅负责委托策略执行)
public class OrderService {
private PaymentStrategy paymentStrategy; // 持有策略接口引用
// 动态设置策略(支持运行时切换)
public void setPaymentStrategy(PaymentStrategy strategy) {
this.paymentStrategy = strategy;
}
// 执行支付(完全解耦具体策略)
public void pay() {
if (paymentStrategy == null) {
throw new IllegalStateException("请先选择支付方式");
}
paymentStrategy.pay(); // 委托给具体策略执行
}
}
// 使用示例
public class Client {
public static void main(String[] args) {
OrderService orderService = new OrderService();
// 选择支付宝支付
orderService.setPaymentStrategy(new AlipayStrategy());
orderService.pay(); // 输出:调用支付宝支付接口,完成支付
// 切换为微信支付
orderService.setPaymentStrategy(new WechatPayStrategy());
orderService.pay(); // 输出:调用微信支付接口,生成支付二维码
// 切换为信用卡支付
orderService.setPaymentStrategy(new CreditCardStrategy());
orderService.pay(); // 输出:调用银行接口,验证信用卡信息并支付
}
}
优势:
- 消除条件判断 :通过策略接口委托调用,避免了冗长的
if-else
分支; - 高扩展性 :新增支付方式(如
UnionPayStrategy
)只需实现PaymentStrategy
接口,无需修改现有代码; - 低耦合:支付逻辑封装在独立策略类中,与订单服务解耦,便于单独测试和维护;
- 行为复用:策略类可被其他业务(如退款服务)复用,减少重复代码。
局限:
- 类数量增加:若策略数量过多(如超过10种),会导致类膨胀,需合理设计(如结合工厂模式);
- 策略初始化成本:若策略需要依赖大量参数(如支付配置),可能需要额外处理(如通过构造函数注入);
- 客户端需了解策略差异:客户端需知道所有策略的存在,才能选择合适的策略(可通过上下文提供默认策略缓解)。
模式变体
-
枚举策略:利用Java枚举特性,将每个策略定义为枚举值并实现策略接口(适合轻量级、固定的策略集合);
javaenum PaymentTypeEnum implements PaymentStrategy { ALIPAY { @Override public void pay() { /* 支付宝逻辑 */ } }, WECHAT_PAY { @Override public void pay() { /* 微信逻辑 */ } }; }
-
静态策略(单例策略):无状态的策略类通过单例模式创建,减少对象实例化开销(适合无状态的策略);
-
策略工厂:通过工厂类动态创建策略对象(解耦策略的创建与使用,适合策略需要根据参数动态选择的场景);
javaclass StrategyFactory { public static PaymentStrategy getStrategy(String type) { switch (type) { case "ALIPAY": return new AlipayStrategy(); case "WECHAT_PAY": return new WechatPayStrategy(); default: throw new IllegalArgumentException("无效支付方式"); } } }
-
组合策略:通过组合多个简单策略实现复杂逻辑(适合策略间有依赖或需要动态叠加的场景)。
最佳实践
建议 | 理由 |
---|---|
策略接口保持稳定 | 策略接口是客户端与策略交互的契约,频繁修改会影响所有策略实现类 |
具体策略尽量无状态 | 无状态的策略类可通过单例复用(如AlipayStrategy.INSTANCE ),减少内存开销 |
上下文避免暴露策略细节 | 上下文仅暴露执行策略的方法(如pay() ),隐藏策略的创建和切换逻辑(通过工厂或构建器优化) |
为策略添加文档说明 | 明确每个策略的适用场景和约束(如"信用卡支付需验证CVV"),帮助客户端正确选择 |
结合工厂模式创建策略 | 当策略创建逻辑复杂(如依赖配置、数据库查询)时,通过工厂类封装创建过程 |
一句话总结
策略模式通过将算法族封装为独立的策略类并动态切换,彻底解决了传统实现中条件判断冗余、扩展性差的问题,是实现灵活业务逻辑的经典解决方案。
如果关注Java设计模式内容,可以查阅作者的其他Java设计模式系列文章。😊