定义
策略模式(Strategy Pattern)是指定义了算法家族,将算法逻辑分别封装起来,让他们之间可以相互替换,让算法的变化不会影响到使用算法的用户。
可以避免多重分支的if…else…和switch语句。
应用场景
- 假如系统中有很多类,而他们的区别仅仅在于他们的行为不同;
- 一个系统需要动态地在几种算法中选择一种。
案例一: 针对订单的不同支付方式
UML类图
代码实现
Order 类
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 MsgResult pay(String key) {
Payment payment = PayStrategy.get(key);
System.out.println("欢迎使用" + payment.getName());
System.out.println("本次交易金额为:" + amount + ",开始扣款....");
return payment.pay(uid, amount);
}
}
MsgResult 类
public class MsgResult {
private Integer code;
private String msg;
private Object data;
public MsgResult(Integer code, String msg, Object data) {
this.code = code;
this.msg = msg;
this.data = data;
}
@Override
public String toString() {
return "支付状态:[" + code + "]," + msg +
",交易详情:" + data;
}
}
PayStrategy 类
public class PayStrategy {
/**
* 事先已知各种支付类型
*/
public static final String ALI_PAY = "Alipay";
public static final String JD_PAY = "Jdpay";
public static final String UNION_PAY = "UnionPay";
public static final String Wechat_PAY = "WechatPay";
public static final String DEFAULT_PAY = ALI_PAY;
private static Map<String, Payment> payStrategy = new HashMap<>();
static {
payStrategy.put(ALI_PAY, new AliPay());
payStrategy.put(JD_PAY, new JDPay());
payStrategy.put(UNION_PAY, new UnionPay());
payStrategy.put(Wechat_PAY, new WechatPay());
}
/**
* 通过统一入口实现动态策略
*
* @param payKey
* @return
*/
public static Payment get(String payKey) {
if (!payStrategy.containsKey(payKey)) {
return payStrategy.get(DEFAULT_PAY);
}
return payStrategy.get(payKey);
}
}
Payment 类
public abstract class Payment {
/**
* 获取支付方式名称
*/
public abstract String getName();
/**
* 获取余额
*/
protected abstract double queryBalance(String uid);
/**
* 支付
*/
public MsgResult pay(String uid, double amount) {
if (queryBalance(uid) < amount) {
return new MsgResult(500, "支付失败", "余额不足");
}
return new MsgResult(200, "支付成功", "支付金额:" + amount);
}
}
AliPay 类
public class AliPay extends Payment {
@Override
public String getName() {
return "支付宝";
}
@Override
protected double queryBalance(String uid) {
return 5000;
}
}
JDPay 类
public class JDPay extends Payment {
@Override
public String getName() {
return "京东白条";
}
@Override
protected double queryBalance(String uid) {
return 200;
}
}
UnionPay 类
public class UnionPay extends Payment {
@Override
public String getName() {
return "银联支付";
}
@Override
protected double queryBalance(String uid) {
return 120;
}
}
WechatPay 类
public class WechatPay extends Payment {
@Override
public String getName() {
return "微信支付";
}
@Override
protected double queryBalance(String uid) {
return 256;
}
}
测试类
public class StrategyTest {
public static void main(String[] args) {
Order order = new Order("1", "2019111900000009", 324.45);
MsgResult msg = order.pay(PayStrategy.ALI_PAY);
System.out.println(msg);
}
}
输出结果
欢迎使用支付宝
本次交易金额为:324.45,开始扣款....
支付状态:[200],支付成功,交易详情:支付金额:324.45
案例二: 针对促销的不同优惠活动
UML类图
代码实现
PormotionActivity 类
public class PromotionActivity {
/**
* 促销策略
*/
private PromotionStrategy promotionStrategy;
public PromotionActivity(PromotionStrategy promotionStrategy) {
this.promotionStrategy = promotionStrategy;
}
public void excute() {
promotionStrategy.doPromotion();
}
}
PromotionStrategyFactory 类 (简单工厂模式)
public class PromotionStrategyFactory {
/**
* 事前已知各种促销策略
*/
private static Map<String, PromotionStrategy> PROMOTION_STRATEGY_MAP = new HashMap<>();
static {
PROMOTION_STRATEGY_MAP.put(PromotionKey.COUPON, new CouponStrategy());
PROMOTION_STRATEGY_MAP.put(PromotionKey.CASHBACK, new CashBackStrategy());
PROMOTION_STRATEGY_MAP.put(PromotionKey.GROUPBUY, new GroupBuyStrategy());
}
private static final PromotionStrategy NON_PROMOTION = new EmptyStrategy();
public PromotionStrategyFactory() {
}
public static PromotionStrategy getPromotionStrategy(String promotionKey) {
PromotionStrategy promotionStrategy = PROMOTION_STRATEGY_MAP.get(promotionKey);
return promotionStrategy == null ? NON_PROMOTION : promotionStrategy;
}
private interface PromotionKey {
String COUPON = "COUPON";
String CASHBACK = "CASHBACK";
String GROUPBUY = "GROUPBUY";
}
}
PromotionStrategy 类
public interface PromotionStrategy {
/**
* 促销
*/
void doPromotion();
}
CashBackStrategy 类
public class CashBackStrategy implements PromotionStrategy {
@Override
public void doPromotion() {
System.out.println("返现促销,返回的金额转到支付宝账号");
}
}
CouponStrategy 类
public class CouponStrategy implements PromotionStrategy {
@Override
public void doPromotion() {
System.out.println("领取优惠卷,课程价格直接减去优惠卷面值抵扣");
}
}
EmptyStrategy 类
public class EmptyStrategy implements PromotionStrategy {
@Override
public void doPromotion() {
System.out.println("无优惠活动");
}
}
GroupBuyStrategy 类
public class GroupBuyStrategy implements PromotionStrategy {
@Override
public void doPromotion() {
System.out.println("拼团,满20人成团,全团享受团购价格");
}
}
在源码中的体现
Comparator接口的compare()方法, 就是一个策略抽象的实现:
public interface Comparator<T> {
int compare(T o1, T o2);
...
}
Comparator抽象西面有飞铲过的实现类, 我们经常把Comparator作为参数传入作为排序策略,
例如Arrays类的parallelSort()方法:
public class Arrays {
...
public static <T> void parallelSort(T[] a, int fromIndex, int toIndex, Comparator<? super T> cmp) {
...
}
...
}
还有TreeMap 的构造方法:
public class TreeMap<K,V> extends AbstractMap<K,V> implements NavigableMap<K,V>, Cloneable, java.io.Serializable {
...
public TreeMap(Comparator<? super K> comparator) {
this.comparator = comparator;
}
...
}
优点
- 策略模式符合开闭原则;
- 避免使用多重条件转移语句, 如 if…else…语句、switchyuju;
- 使用策略模式可以提高算法的保密性和安全性。
缺点
- 客户端必须知道所有的策略,并且自行决定使用哪一个策略;
- 代码中会产生非常多的策略类,增加维护难度。
和其他设计模式的结合
委派模式 + 策略模式
策略模式 + 构造器,如案例一
策略模式 + 简单工厂模式,如案例二