设计模式(三)之策略模式(Strategy Pattern)深入浅出
策略模式定义:
- 是指定义了算法家族、分别封装起来,让它们之间可以互相替换,此模式让算法的变化不会影响到使用算法的用户。
- 属于行为型模式。
策略模式优点:可以避免多重分支的if...else...和switch语句
策略模式的使用场景:
- 假如系统中有很多类,而他们的区别仅仅在于他们的行为不同。
- 一个系统需要动态的在几种算法中选择一种。
策略模式案例:
- JDK中Comparator接口中的int compare(T o1, T o2);方法,在Arrays、TreeMap里可以自定义排序规则
Arrays.class
TreeMap.class
- Spring中的Resource接口
- Spring中InstantiationStrategy接口,主要对类进行初始化策略,有两个策略实现类,它们不是平级而是继承关系(策略模式中不同策略也可以继承)
- CglibSubclassingInstantiationStrategy:Cglib的初始方式
- SimpleInstantiationStrategy:JDK的初始化方式
类图
生活场景案例
案例:购买东西有活动时,会有抵用券、返现、拼团等减免金额的策略
优惠策略抽象接口
/** * @ClassName PromotionStrategy * @Author 周聪 * @Date 2021/1/10 17:58 * @Version 1.0 * @Description 优惠策略的抽象 */ public interface PromotionStrategy { /** * 执行优惠 */ void doPromotion(); }
没有优惠
/** * @ClassName EmptyStrategy * @Author 周聪 * @Date 2021/1/10 17:59 * @Version 1.0 * @Description 无优惠 */ public class EmptyStrategy implements PromotionStrategy{ @Override public void doPromotion() { System.out.println("无促销活动"); } }
抵用券
/** * @ClassName CouponStrategy * @Author 周聪 * @Date 2021/1/10 18:01 * @Version 1.0 * @Description 优惠券抵扣 */ public class CouponStrategy implements PromotionStrategy { @Override public void doPromotion() { System.out.println("领取优惠券,课程的价格直接减去优惠券面值抵扣"); } }
返现
/** * @ClassName CashbackStrategy * @Author 周聪 * @Date 2021/1/10 18:04 * @Version 1.0 * @Description 返现 */ public class CashbackStrategy implements PromotionStrategy { @Override public void doPromotion() { System.out.println("返现促销,返回的金额转到支付宝账号"); } }
拼团
/** * @ClassName GroupBuyStrategy * @Author 周聪 * @Date 2021/1/10 18:05 * @Version 1.0 * @Description 团购 */ public class GroupBuyStrategy implements PromotionStrategy{ @Override public void doPromotion() { System.out.println("拼团,满20人成团,全团享受团购价格"); } }
优惠活动
/** * @ClassName PromotionActivity * @Author 周聪 * @Date 2021/1/10 18:07 * @Version 1.0 * @Description 优惠活动 */ public class PromotionActivity { PromotionStrategy promotionStrategy; public PromotionActivity(PromotionStrategy promotionStrategy){ this.promotionStrategy = promotionStrategy; } /** * 执行优惠活动 */ public void execute(){ this.promotionStrategy.doPromotion(); } }
测试一
public static void main(String[] args) { // 618优惠券活动 PromotionActivity activity618 = new PromotionActivity(new CouponStrategy()); activity618.execute(); // 双11返现活动 PromotionActivity activity1111 = new PromotionActivity(new CashbackStrategy()); activity1111.execute(); }
测试二
public static void main(String[] args) { PromotionActivity promotionActivity = null; String promotionKey = "COUPON"; if (StringUtils.equals(promotionKey,"COUPON")){ promotionActivity = new PromotionActivity(new CouponStrategy()); }else if (StringUtils.equals(promotionKey,"CASHBACK")){ promotionActivity = new PromotionActivity(new CashbackStrategy()); } // ....... promotionActivity.execute(); }
简单实现完发现还可以通过单例模式+简单工厂模式简化代码,用唯一标志选择策略
工厂类
/** * @ClassName PromotionStrategyFactory * @Author 周聪 * @Date 2021/1/10 18:28 * @Version 1.0 * @Description 简单工厂+ 注册式饿汉式单例 */ public class PromotionStrategyFactory { private static final Map<String,PromotionStrategy> PROMOTION_STRATEGY_MAP = new ConcurrentHashMap<String,PromotionStrategy>(); private static final PromotionStrategy NON_PROMOTION = new EmptyStrategy(); 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 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"; } }
测试
public static void main(String[] args) { String promotionKey = "GROUPBUY"; PromotionActivity promotionActivity = new PromotionActivity(PromotionStrategyFactory.getPromotionStrategy(promotionKey)); promotionActivity.execute(); }
附上类结构图
业务场景案例
案例:用户下单支付,可以选择多种支付渠道
支付抽象类
/** * @ClassName Payment * @Author 周聪 * @Date 2021/1/10 18:55 * @Version 1.0 * @Description 支付抽象 */ public abstract class Payment { /** * 支付信息 * @return */ public abstract String getName(); /** * 余额 * @param uid * @return */ protected abstract double queryBalance(String uid); /** * 支付 * @param uid * @param amount * @return */ public MsgResult pay(String uid,double amount){ if (queryBalance(uid) < amount){ return new MsgResult(500,"支付失败","余额不足"); }else { return new MsgResult(200,"支付成功","支付金额: " + amount); } } }
支付宝支付
/** * @ClassName AliPay * @Author 周聪 * @Date 2021/1/10 18:54 * @Version 1.0 * @Description 支付宝支付 */ public class AliPay extends Payment{ @Override public String getName() { return "支付宝"; } @Override protected double queryBalance(String uid) { return 900; } }
京东白条
/** * @ClassName JDPay * @Author 周聪 * @Date 2021/1/10 19:45 * @Version 1.0 * @Description */ public class JDPay extends Payment{ @Override public String getName() { return "京东白条"; } @Override protected double queryBalance(String uid) { return 500; } }
银联支付
/** * @ClassName UnionPay * @Author 周聪 * @Date 2021/1/10 19:47 * @Version 1.0 * @Description 银联支付 */ public class UnionPay extends Payment { @Override public String getName() { return "银联支付"; } @Override protected double queryBalance(String uid) { return 120; } }
微信支付
/** * @ClassName WechatPay * @Author 周聪 * @Date 2021/1/10 19:46 * @Version 1.0 * @Description */ public class WechatPay extends Payment { @Override public String getName() { return "微信支付"; } @Override protected double queryBalance(String uid) { return 256; } }
返回消息类
/** * @ClassName MsgResult * @Author 周聪 * @Date 2021/1/10 18:49 * @Version 1.0 * @Description 返回消息类 */ public class MsgResult { private int code; private Object data; private String msg; public MsgResult(int code, Object data, String msg) { this.code = code; this.data = data; this.msg = msg; } @Override public String toString() { return "MsgResult{" + "code=" + code + ", data=" + data + ", msg='" + msg + '\'' + '}'; } }
订单类
/** * @ClassName Order * @Author 周聪 * @Date 2021/1/10 18:48 * @Version 1.0 * @Description */ 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 payKey){ Payment payment = PayStrategy.get(payKey); System.out.println("欢迎使用" + payment.getName()); System.out.println("本次交易金额为:" + amount + ",开始扣款..."); return payment.pay(uid,amount); } @Override public String toString() { return "Order{" + "uid='" + uid + '\'' + ", orderId='" + orderId + '\'' + ", amount=" + amount + '}'; } }
支付策略工厂
/** * @ClassName PayStrategy * @Author 周聪 * @Date 2021/1/10 19:51 * @Version 1.0 * @Description 支付策略工厂 */ public class PayStrategy { public static final String ALI_PAY = "AliPay"; public static final String JD_PAY = "JDPay"; public static final String WECHAT_PAY = "WchatPay"; public static final String UNION_PAY = "UnionPay"; public static final String DEFAULT_PAY = "AliPay"; private static Map<String,Payment> payStrategy = new HashMap<String,Payment>(); static { payStrategy.put(ALI_PAY,new AliPay()); payStrategy.put(JD_PAY,new JDPay()); payStrategy.put(WECHAT_PAY,new WechatPay()); payStrategy.put(UNION_PAY,new UnionPay()); payStrategy.put(DEFAULT_PAY,new AliPay()); } public static Payment get(String payKey){ if (!payStrategy.containsKey(payKey)){ return payStrategy.get(DEFAULT_PAY); } return payStrategy.get(payKey); } }
测试
/** * @ClassName PayStrategyTest * @Author 周聪 * @Date 2021/1/10 19:48 * @Version 1.0 * @Description */ public class PayStrategyTest { public static void main(String[] args) { Order order = new Order("1", "2021110", 1342.45); MsgResult result = order.pay(PayStrategy.ALI_PAY); System.out.println(result); } }
附上类结构图:
总结
策略模式的优点:
- 策略模式符合开闭原则。
- 避免使用多重条件转移语句,如if...else...语句、switch语句。
- 使用策略模式可以提高算法的保密性和安全性。
策略模式的缺点:
- 客户端必须知道所有的策略,并且用户自行决定使用哪一个策略类。
- 代码中会产生非常多策略类,增加维护难度。
以上对策略模式的介绍到此结束,欢迎批评指正。 附:源码地址