深入理解23种设计模式(22) -- 策略模式

540 阅读3分钟

介绍

  1. 策略模式 :(Strategy Pattern) 中定义算法族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化独立于使用算法的用户
  2. 这个算法体现了几个设计原则,第一:把变化的代码从不变的代码中国好分离出来,第二:针对接口编程,而不是实体类,(定义了策略接口)第三:多用组合 少用继承 (客户使用组合的方式使用策略)

在这里插入图片描述

  • Context :是上下文,用一个ConcreteStrategy来配置,维护一个对Strategy对象的引用
  • Strategy:是策略类,用于定义所有支持算法的公共接口
  • ConcreteStrategy是具体策略类,封装了具体的算法或行为,继承于Strategy。

案例

支付案例:

  1. 在我们日常项目中我们会遇到 接入 微信支付、支付宝支付、银行卡支付、苹果支付等

定义策略接口

public interface PayStrategy {

    /**
     * 支付 统一下单接口
     * @param orderId
     * @param price
     */
    void unifiedOrder(Integer orderId, BigDecimal price);


    /**
     * 退款接口
     * @param orderId
     * @return
     */
    boolean refund(Integer orderId);


}

策略实现类 微信支付

public class WeChatPayStrategy implements PayStrategy {
    @Override
    public void unifiedOrder(Integer orderId, BigDecimal price) {
        System.out.println("微信下单支付");
    }


    @Override
    public boolean refund(Integer orderId) {
        System.out.println("微信退款成功");
        return true;
    }

}

策略实现类 支付宝支付

public class AlipayPayStrategy implements PayStrategy{
    @Override
    public void unifiedOrder(Integer orderId, BigDecimal price) {
        System.out.println("支付宝下单支付");
    }

    @Override
    public boolean refund(Integer orderId) {
        System.out.println("支付宝退款成功");
        return true;
    }

}

策略实现类 银行卡支付

public class CardPayStrategy implements PayStrategy{
    @Override
    public void unifiedOrder(Integer orderId, BigDecimal price) {
        System.out.println("银行卡下单支付");
    }



    @Override
    public boolean refund(Integer orderId) {
        System.out.println("银行卡退款成功");
        return true;
    }


}

策略实现类 苹果支付

public class ApplePayStrategy implements PayStrategy{
    @Override
    public void unifiedOrder(Integer orderId, BigDecimal price) {
        System.out.println("苹果下单支付");
    }



    @Override
    public boolean refund(Integer orderId) {
        System.out.println("苹果退款成功");
        return true;
    }

}

Context 类

public class PayContext {

    PayStrategy payStrategy;

    public PayContext(PayStrategy payStrategy) {
        this.payStrategy = payStrategy;
    }

    public void getPay(){
        payStrategy.unifiedOrder(new Random(10).nextInt(),new BigDecimal("1"));
    }

    public void getRefund(){
        payStrategy.refund(new Random(10).nextInt());
    }
}

客户端

public class Client {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.print("请输入支付方式(1微信/2支付宝/3银行卡/4苹果支付):");
        int in = scanner.nextInt();
        PayContext payContext = null;
        switch (in){
            case 1:
                payContext = new PayContext(new WeChatPayStrategy());
                break;
            case 2:
                payContext = new PayContext(new AlipayPayStrategy());
                break;
            case 3:
                payContext = new PayContext(new CardPayStrategy());
                break;
            case 4:
                payContext = new PayContext(new ApplePayStrategy());
                break;
        }
        payContext.getPay();
        payContext.getRefund();
    }
}

在这里插入图片描述

优点和缺点

优点:

1)算法可以自由切换
2)避免使用多重条件判断(如果不用策略模式我们可能会使用多重条件语句,不利于维护)
3)扩展性良好,增加一个策略只需实现接口即可

缺点:

 1)策略类数量会增多,每个策略都是一个类
 2)所有的策略类都需要对外暴露

适用场景:

 1) 算法需要自由切换的场景: 商场促销方式,打折、满减等

JDK中实现

  1. 比较器Comparator
Integer[] data = {12, 2, 3, 2, 4, 5, 1};
        // 实现降序排序
Arrays.sort(data, new Comparator<Integer>() {
     @Override
     public int compare(Integer o1, Integer o2) {
            return o2 - o1;
     }
});
System.out.println(Arrays.toString(data)); //[12, 5, 4, 3, 2, 2, 1]

Arrays.sort();中可以指定比较器,实现comparator接口的比较器,作为对象传入

  1. ThreadPoolExecutor中的四种拒绝策略
/**
 * 自定义拒绝策略
 **/
 ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 2, 60L, TimeUnit.SECONDS, new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory(), new RejectedExecutionHandler() {
            @Override
            public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                
            }
        });


//也可以实现它的子类


ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 2, 60L, TimeUnit.SECONDS, new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy);

这里使用的就是策略模式。 在这里插入图片描述 RejectedExecutionHandler 的实现类

  • AbortPolicy:直接抛出异常。
  • CallerRunsPolicy:只用调用者所在线程来运行任务。
  • DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务。
  • DiscardPolicy:不处理,丢弃掉。

github Demo地址 : ~~~传送门~~~

个人博客地址:blog.yanxiaolong.cn/