策略模式(Strategy Pattern)是指定义了算法家族并分别封装起来,让它们之间可以相互替换,此模式使得算法的变化不会影响使用算法的用户。
一个常见的应用场景就是大家在支付时会提示选择支付方式,如果用户未选,系统也会使用默认的支付方式进行结算。来看一下类图,如下图所示。
下面我们用策略模式来模拟此业务场景。
创建 Payment 抽象类,定义支付规范和支付逻辑:
package com.yjw.demo.pattern.strategy.pay;import com.yjw.demo.pattern.strategy.PayState;/*** 支付渠道*/public abstract class Payment {/*** 支付类型*/public abstract String getName();/*** 查询余额** @param uid* @return*/protected abstract double queryBalance(String uid);/*** 扣款支付** @param uid* @param amount*/public PayState pay(String uid, Double amount) {if (queryBalance(uid) < amount) {return new PayState(500, "支付失败", "余额不足");}return new PayState(200, "支付成功", "支付金额:" + amount);}}
分别创建具体的支付方式,支付宝支付类 AliPay:
package com.yjw.demo.pattern.strategy.pay;public class AliPay extends Payment {@Overridepublic String getName() {return "支付宝";}@Overrideprotected double queryBalance(String uid) {return 900;}}
微信支付类 WechatPay:
package com.yjw.demo.pattern.strategy.pay;public class WechatPay extends Payment {@Overridepublic String getName() {return "微信支付";}@Overrideprotected double queryBalance(String uid) {return 256;}}
银联支付类 UnionPay:
package com.yjw.demo.pattern.strategy.pay;public class UnionPay extends Payment {@Overridepublic String getName() {return "银联支付";}@Overrideprotected double queryBalance(String uid) {return 120;}}
创建支付状态的包装类 PayState:
package com.yjw.demo.pattern.strategy;public class PayState {private int code;private Object data;private String msg;public PayState(int code, Object data, String msg) {this.code = code;this.data = data;this.msg = msg;}@Overridepublic String toString() {return ("支付状态:[" + code + "]," + msg + ",交易详情:" + data);}}
创建支付策略管理类 PayStrategy:
package com.yjw.demo.pattern.strategy;import com.yjw.demo.pattern.strategy.pay.AliPay;import com.yjw.demo.pattern.strategy.pay.Payment;import com.yjw.demo.pattern.strategy.pay.UnionPay;import com.yjw.demo.pattern.strategy.pay.WechatPay;import java.util.HashMap;import java.util.Map;public class PayStrategy {public static final String DEFAULT_PAY = "AliPay";public static final String ALI_PAY = "AliPay";public static final String WECHAT_PAY = "WechatPay";public static final String UNION_PAY = "UnionPay";private static Map<String, Payment> payStrategy = new HashMap<>();static {payStrategy.put(DEFAULT_PAY, new AliPay());payStrategy.put(ALI_PAY, new AliPay());payStrategy.put(WECHAT_PAY, new WechatPay());payStrategy.put(UNION_PAY, new UnionPay());}public static Payment get(String payKey) {if (!payStrategy.containsKey(payKey)) {return payStrategy.get(DEFAULT_PAY);}return payStrategy.get(payKey);}}
创建订单类 Order:
package com.yjw.demo.pattern.strategy;import com.yjw.demo.pattern.strategy.pay.Payment;/*** 模拟订单支付场景** @author yinjianwei* @date 2018/12/13*/public class Order {private String uid;private String orderId;private Double amount;public Order(String uid, String orderId, Double amount) {this.uid = uid;this.orderId = orderId;this.amount = amount;}public PayState pay() {return pay(PayStrategy.DEFAULT_PAY);}public PayState pay(String payKey) {Payment payment = PayStrategy.get(payKey);System.out.println("欢迎使用" + payment.getName());System.out.println("本次交易金额为:" + amount + ",开始扣款。。。");return payment.pay(uid, amount);}}
测试代码如下:
package com.yjw.demo.pattern.strategy;public class PayStrategyTest {public static void main(String[] args) {Order order = new Order("1", "20191119163020300", 300.87);System.out.println(order.pay(PayStrategy.ALI_PAY));}}
运行结果如下图所示。

摘录:《Spring 5 核心原理与30个类手写实战》来自文艺界的Tom老师的书籍。
看到组内分享的一篇描述策略模式的文章(https://blog.csdn.net/qq_23934475/article/details/83088332),使用 Java 8 的函数式接口、Lambda 表达式改写策略模式,这种方式可以使用在平时的业务代码中,它类似匿名内部类的实现,省略了一些策略类的编写,减少了类的数量,但是如果是编写框架,需要制定严格的策略,不建议使用这种方式,还是自定义策略类比较好,便于归类、理解,大家一看到以 Strategy 结尾的类就知道了这个类是策略类了。
作者:殷建卫 链接:https://www.yuque.com/yinjianwei/vyrvkf/hbhayl 来源:殷建卫 - 架构笔记 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
