设计模式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-策略模式与责任链模式详解的主要内容,如果未能解决你的问题,请参考以下文章

工厂模式策略者模式责任链模式综合应用

前端设计模式之责任链模式

责任链和策略设计模式-基于Java编程语言

GoF 23 种设计模式之策略模式和责任链模式

GoF 23 种设计模式之策略模式和责任链模式

设计模式之责任链模式