设计模式10-策略模式与责任链模式详解
Posted wfdespace
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式10-策略模式与责任链模式详解相关的知识,希望对你有一定的参考价值。
1.10.策略模式与责任链模式详解
1.10.1.策略模式详解
时长:1h15min
10.1.1.策略模式的定义
定义:
策略模式【Strategy Pattern】,又叫政策模式【Policy Pattern】,它是将定义的算法家族,分别封装起来,让它们之间可以相互替换,从而
让算法的变化不会影响到使用算法的用户。
可以避免多重分支的if...else...和switch语句。
属于行为型模式。
10.1.1.1.策略模式在生活中应用场景
阶梯个税【工资收入不同,个税算法不同】
移动支付方式选择【微信,支付宝,银联】
出行交通方式选择【火车,飞机,汽车,轮船】
10.1.1.1、2.策略模式的应用场景
1.假如系统中有很多类,而他们的区别仅仅在于他们的行为 不同。
2.一个系统需要动态地在几种算法中选择一种。
3.需要屏蔽算法规则。
10.1.2.策略模式的通用实现
10.1.2.1.类图设计
10.1.2.2.代码实现
1.顶层策略接口
package com.wf.strategy.general; /** * @ClassName IStrategy * @Description 顶层策略接口 * @Author wf * @Date 2020/6/18 10:11 * @Version 1.0 */ public interface IStrategy { /** * 算法接口 */ void algorithm(); }
2.策略子类实现
package com.wf.strategy.general; /** * @ClassName ConcreteStrategyA * @Description 具体策略子类A * @Author wf * @Date 2020/6/18 10:13 * @Version 1.0 */ public class ConcreteStrategyA implements IStrategy { @Override public void algorithm() { System.out.println("这是算法A"); } } package com.wf.strategy.general; /** * @ClassName ConcreteStrategyB * @Description 具体策略子类B * @Author wf * @Date 2020/6/18 10:13 * @Version 1.0 */ public class ConcreteStrategyB implements IStrategy { @Override public void algorithm() { System.out.println("这是算法B"); } }
3.上下文对象
package com.wf.strategy.general; /** * @ClassName Context * @Description 上下文对象 * @Author wf * @Date 2020/6/18 10:14 * @Version 1.0 */ public class Context { private IStrategy strategy; public Context(IStrategy strategy) { this.strategy = strategy; } //由构造器中传参实现子类类型,来决定选择哪一种算法 public void algorithm(){ this.strategy.algorithm(); } }
4.测试类
package com.wf.strategy.general; /** * @ClassName Test * @Description 测试类 * @Author wf * @Date 2020/6/18 10:15 * @Version 1.0 */ public class Test { public static void main(String[] args) { //使用时,客户选择一种策略 IStrategy strategy = new ConcreteStrategyA(); //封装到上下文中 Context context = new Context(strategy); //调用策略方法 context.algorithm(); } }
测试结果如下:
10.1.3.策略模式的实现示例之促销案例
10.1.3.1.代码实现
1.顶层接口
package com.wf.strategy.demo.promotion; /** * @ClassName IPromotionStrategy * @Description 促销策略接口 * @Author wf * @Date 2020/6/18 10:31 * @Version 1.0 */ public interface IPromotionStrategy { /** * 促销方法 */ void doPromotion(); }
2.实现子类
package com.wf.strategy.demo.promotion; /** * @ClassName GroupPurchaseStrategy * @Description 团购促销 * @Author wf * @Date 2020/6/18 10:36 * @Version 1.0 */ public class GroupPurchaseStrategy implements IPromotionStrategy{ @Override public void doPromotion() { System.out.println("5人成团,可以优惠"); } } package com.wf.strategy.demo.promotion; /** * @ClassName CashRollbackStrategy * @Description 返现促销 * @Author wf * @Date 2020/6/18 10:34 * @Version 1.0 */ public class CashRollbackStrategy implements IPromotionStrategy { @Override public void doPromotion() { System.out.println("返现,直接打款到支付宝帐号"); } } package com.wf.strategy.demo.promotion; /** * @ClassName CouponStrategy * @Description 优惠券促销方式 * @Author wf * @Date 2020/6/18 10:33 * @Version 1.0 */ public class CouponStrategy implements IPromotionStrategy { @Override public void doPromotion() { System.out.println("使用优惠券抵扣"); } } package com.wf.strategy.demo.promotion; /** * @ClassName EmptyStrategy * @Description 无优惠购买 * @Author wf * @Date 2020/6/18 10:37 * @Version 1.0 */ public class EmptyStrategy implements IPromotionStrategy { @Override public void doPromotion() { System.out.println("原价购买,无优惠"); } }
3.测试类
public static void main(String[] args) { String promotion = ""; IPromotionStrategy strategy = null; if("团购".equals(promotion)){ strategy = new GroupPurchaseStrategy(); }else if("".equals(promotion)){ //... strategy = new EmptyStrategy(); } strategy.doPromotion(); }
测试结果:
说明:
这里并没有使用策略模式,而是通过分支判断,多态的方式来实现。
4.策略模式运用---增加上下文对象
package com.wf.strategy.demo.promotion; /** * @ClassName PromotionActivity * @Description 上下文对象,促销活动 * @Author wf * @Date 2020/6/18 10:45 * @Version 1.0 */ public class PromotionActivity { private IPromotionStrategy strategy; public PromotionActivity(IPromotionStrategy strategy) { this.strategy = strategy; } public void execute(){ strategy.doPromotion(); } }
修改测试代码如下:
public static void main(String[] args) { String promotion = ""; PromotionActivity activity = null; if("团购".equals(promotion)){ activity = new PromotionActivity(new GroupPurchaseStrategy()); }else if("".equals(promotion)){ //... activity = new PromotionActivity(new EmptyStrategy()); } activity.execute(); //说明: //这里仍然需要进行if...else分支判断,代码仍然不够优雅 //解决这个问题,通常使用策略模式 + 简单工厂模式 }
说明:
//这里仍然需要进行if...else分支判断,代码仍然不够优雅 //解决这个问题,通常使用策略模式 + 简单工厂模式
5.引入简单工厂优化
package com.wf.strategy.demo.promotion; import java.util.HashMap; import java.util.Map; import java.util.Set; /** * @ClassName PromotionStrategyFactory * @Description 上下文对象创建工厂 * @Author wf * @Date 2020/6/18 10:52 * @Version 1.0 */ public class PromotionStrategyFactory { private static Map<String,IPromotionStrategy> promotionStrategyMap = new HashMap<String,IPromotionStrategy>(); private static final IPromotionStrategy EMPTY = new EmptyStrategy(); static{ promotionStrategyMap.put(PromotionKey.COUPON,new CouponStrategy()); promotionStrategyMap.put(PromotionKey.CASH_ROLLBACK,new CashRollbackStrategy()); promotionStrategyMap.put(PromotionKey.GROUP_PURCHASE,new GroupPurchaseStrategy()); } private PromotionStrategyFactory(){} public static IPromotionStrategy getPromotionStrategy(String promotionKey){ IPromotionStrategy strategy = promotionStrategyMap.get(promotionKey); return strategy == null ? EMPTY : strategy; } //定义内部接口,定义key private interface PromotionKey{ String COUPON = "COUPON"; String CASH_ROLLBACK = "CASH_ROLLBACK"; String GROUP_PURCHASE = "GROUP_PURCHASE"; } public Set<String> getPromotionKeys(){ return promotionStrategyMap.keySet(); } }
修改测试类:
public static void main(String[] args) { String promotionKey = "COUPON"; IPromotionStrategy strategy = PromotionStrategyFactory.getPromotionStrategy(promotionKey); strategy.doPromotion(); }
测试结果如下:
说明:
分支判断,移到工厂类中去处理。
10.1.3.2.系统类图
10.1.4.策略模式的实现示例之支付方式选择案例
10.1.4.1.代码实现
1.顶层接口
package com.wf.strategy.demo.pay.payport; import com.wf.strategy.demo.pay.MsgResult; /** * @ClassName Payment * @Description 支付抽象接口 * @Author wf * @Date 2020/6/18 11:31 * @Version 1.0 */ public abstract class Payment { public abstract String getName(); public MsgResult pay(String uid, double amount){ //查询余额是否足够 if(queryBalance(uid) < amount){ return new MsgResult(500,"支付失败","余额不足"); } return new MsgResult(200,"支付成功","支付金额:"+amount); } protected abstract double queryBalance(String uid); }
2.子类实现
package com.wf.strategy.demo.pay.payport; /** * @ClassName WechatPay * @Description 微信支付 * @Author wf * @Date 2020/6/18 14:27 * @Version 1.0 */ public class WechatPay extends Payment { @Override public String getName() { return "微信支付"; } @Override protected double queryBalance(String uid) { return 500; } } package com.wf.strategy.demo.pay.payport; /** * @ClassName JDPay * @Description 京东白条支付 * @Author wf * @Date 2020/6/18 14:25 * @Version 1.0 */ public class JDPay extends Payment { @Override public String getName() { return "京东白条"; } @Override protected double queryBalance(String uid) { return 500; } } package com.wf.strategy.demo.pay.payport; /** * @ClassName BankUnionPay * @Description 银联支付 * @Author wf * @Date 2020/6/18 14:28 * @Version 1.0 */ public class BankUnionPay extends Payment { @Override public String getName() { return "银联支付"; } @Override protected double queryBalance(String uid) { return 120; } } package com.wf.strategy.demo.pay.payport; /** * @ClassName AliPay * @Description 支付宝支付 * @Author wf * @Date 2020/6/18 14:23 * @Version 1.0 */ public class AliPay extends Payment { @Override public String getName() { return "支付宝"; } @Override protected double queryBalance(String uid) { return 900; } }
3.订单类
package com.wf.strategy.demo.pay; import com.wf.strategy.demo.pay.payport.PayStrategy; import com.wf.strategy.demo.pay.payport.Payment; /** * @ClassName Order * @Description 订单类 * @Author wf * @Date 2020/6/18 14:29 * @Version 1.0 */ 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(){ return pay(PayStrategy.DEFAULT_PAY); } public MsgResult pay(String payKey){ Payment payment = PayStrategy.get(payKey); System.out.println("欢迎使用:"+payment.getName()); System.out.println("本次交易金额为:"+amount+",开始扣款"); return payment.pay(uid,amount); } }
4.上下文对象
package com.wf.strategy.demo.pay.payport; import java.util.HashMap; import java.util.Map; /** * @ClassName PayStrategy * @Description 支付策略,上下文对象 * @Author wf * @Date 2020/6/18 14:32 * @Version 1.0 */ public class PayStrategy { public static final String ALI_PAY = "AliPay"; public static final String JD_PAY = "JdPay"; public static final String WECHAT_PAY = "WechatPay"; public static final String BANKUINION_PAY = "BankUnionPay"; public static final String DEFAULT_PAY = "AliPay"; private static Map<String,Payment> strategyMap = new HashMap<String, Payment>(); static { strategyMap.put(ALI_PAY,new AliPay()); strategyMap.put(JD_PAY,new JDPay()); strategyMap.put(WECHAT_PAY,new WechatPay()); strategyMap.put(BANKUINION_PAY,new BankUnionPay()); } public static Payment get(String payKey){ if(!strategyMap.containsKey(payKey)){ return strategyMap.get(DEFAULT_PAY); } return strategyMap.get(payKey); } }
5.结果集po
package com.wf.strategy.demo.pay; /** * @ClassName MsgResult * @Description 结果集 * @Author wf * @Date 2020/6/18 11:36 * @Version 1.0 */ public class MsgResult { private int code; private Object data; private String msg; public MsgResult(int code, String msg, Object data) { this.code = code; this.data = data; this.msg = msg; } @Override public String toString() { return "MsgResult{" + "code=‘" + code + ‘‘‘ + ", data=" + data + ", msg=‘" + msg + ‘‘‘ + ‘}‘; } }
6.测试类
package com.wf.strategy.demo.pay; import com.sun.org.apache.xpath.internal.operations.Or; import com.wf.strategy.demo.pay.payport.PayStrategy; /** * @ClassName Test * @Description 测试类 * @Author wf * @Date 2020/6/18 14:43 * @Version 1.0 */ public class Test { public static void main(String[] args) { Order order = new Order("1","20200618012222",324.5); System.out.println(order.pay(PayStrategy.BANKUINION_PAY)); } }
测试结果如下:
10.1.4.2.类图设计
10.1.5.策略模式在源码中应用
10.1.5.1.jdk中Comparator接口
int compare(T o1, T o2);
表示列表中前后两个元素进行比较,如果返回值大于0,表示升序。
它的实现类,在Arrays中parallelSort方法有定义:
public static <T> void parallelSort(T[] a, Comparator<? super T> cmp) { if (cmp == null) cmp = NaturalOrder.INSTANCE; //默认策略 int n = a.length, p, g; if (n <= MIN_ARRAY_SORT_GRAN || (p = ForkJoinPool.getCommonPoolParallelism()) == 1) TimSort.sort(a, 0, n, cmp, null, 0, 0); else new ArraysParallelSortHelpers.FJObject.Sorter<T> (null, a, (T[])Array.newInstance(a.getClass().getComponentType(), n), 0, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? MIN_ARRAY_SORT_GRAN : g, cmp).invoke(); }
默认策略中调用:
static final class NaturalOrder implements Comparator<Object> { @SuppressWarnings("unchecked") public int compare(Object first, Object second) { return ((Comparable<Object>)first).compareTo(second); } static final NaturalOrder INSTANCE = new NaturalOrder(); }
10.1.5.2.spring中Resource接口
10.1.5.3.spring中InstantiationStrategy接口
10.1.6.策略模式使用总结
10.1.6.1.优缺点总结
优点:
符合开闭原则
避免使用多重条件判断,如:if...else if...,switch
使用策略模式可以提高算法的保密性和安全性。
缺点:
客户端必须要知道所有的策略,并且自行选择使用哪一个策略。
可以通过字典表配置成枚举参数,当用户点击时,弹出所有策略。任选一个。
代码中会增加非常多的策略类,增加维护难度 。
1.10.2.责任链模式详解
以上是关于设计模式10-策略模式与责任链模式详解的主要内容,如果未能解决你的问题,请参考以下文章