• Spring中常见的设计模式——策略模式


      策略模式(Strategy Pattern)是指定义了算法家族病分别封装起来,让他们之间可以互相替换,此模式是的算法的变化不会影响使用算法的用户。

    一、策略模式的应用场景

      策略模式的应用场景如下:

    • 系统中有很多类,而他们的区别仅仅在于行为不同。
    • 一个系统需要动态的在几种算法中选择一种

    二、用策略模式实现选择支付方式的业务场景

      一个常见的应用场景就是大家在支付时会提示选择支付方式,如果用户未选,系统会使用默认的支付方式进行结算。下面我们用策略模式来模拟此业务场景:

    /**
     * 定义支付规范和支付逻辑
     */
    public abstract class Payment {
    
        //支付类型
        public abstract String getName();
    
        //查询余额
        protected abstract double queryBalance(String uid);
    
        //扣款支付
        public PayState pay(String uid, double amount) {
            if (queryBalance(uid) < amount) {
                return new PayState(500, "支付失败", "余额不足");
            }
            return new PayState(200, "支付成功", "支付金额:" + amount);
        }
    }

      扣款支付逻辑简单做一下:

    /**
     * 支付逻辑
     */
    public class PayState {
        private int code;
        private Object data;
        private String msg;
    
        public PayState(int code, String msg, String data) {
            this.code = code;
            this.data = data;
            this.msg = msg;
        }
    
        public String toString() {
            return ("支付状态:[" + code + "]," + msg + ",交易详情:" + data);
        }
    }

      定义两种支付方式:

    /**
     * 支付宝
     */
    public class AliPay extends Payment {
        @Override
        public String getName() {
            return "支付宝";
        }
    
        @Override
        protected double queryBalance(String uid) {
            return 900;
        }
    }
    
    /**
     * 微信支付
     */
    public class WechatPay extends Payment {
        @Override
        public String getName() {
            return "微信支付";
        }
    
        @Override
        protected double queryBalance(String uid) {
            return 256;
        }
    }

      支付策略管理类

    /**
     * 支付策略管理类
     */
    public class PayStrategy {
        public static final String ALI_PAY = "AliPay";
        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(WECHAT_PAY, new WechatPay());
        }
    
        public static Payment get(String payKey) {
            if (!payStrategy.containsKey(payKey)) {
                return payStrategy.get(DEFAULT_PAY);
            }
            return payStrategy.get(payKey);
        }
    }

      创建订单:订单支付时因为支付方式已经在集合内并且可以通过key得到,所以不用switch 和if else进行赘述

    /**
     * 订单类
     */
    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;
        }
    
        //完美解决了switch的过程,不需要写switch和if...else if 
        public PayState pay() {
            return pay(PayStrategy.DEFAULT_PAY);
        }
    
        public PayState pay(String payKey) {
            Payment payment = PayStrategy.get(payKey);
            System.out.println("欢迎使用:" + payment.getName());
            System.out.println("本次交易金额为:" + amount + ",扣款中...");
            return payment.pay(uid, amount);
        }
    }

      测试类:

    public class PayStrategyTest {
        public static void main(String[] args) {
            //创建订单
            Order order = new Order("1", "202001080001", 324.45);
    
            //选择支付方式:支付宝支付
            System.out.println(order.pay(PayStrategy.ALI_PAY));
        }
    }

    三、策略模式在源码中的体现

    1.JDK中的应用

      首先看比较常见的比较器——Compare接口,常用的compare()方法就是常见的策略模式的抽象实现,Comparator接口下面有非常多的实现类,我们把Comparator接口作为传入实现排序策略例如:

    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();
        }

      还有TreeMap类的构造方法:

        public TreeMap(Comparator<? super K> comparator) {
            this.comparator = comparator;
        }

    2.Spring源码中的应用

      Spring的初始化采用了策略模式,不同类型的类采用不同的初始化策略。

    public interface InstantiationStrategy {
        Object instantiate(RootBeanDefinition var1, String var2, BeanFactory var3) throws BeansException;
    
        Object instantiate(RootBeanDefinition var1, String var2, BeanFactory var3, Constructor<?> var4, Object... var5) throws BeansException;
    
        Object instantiate(RootBeanDefinition var1, String var2, BeanFactory var3, Object var4, Method var5, Object... var6) throws BeansException;
    }

    四、策略模式的优缺点

     策略模式的优点如下:

    • 策略模式符合开闭原则。
    • 策略模式可避免使用多重条件语句,如switch if else。
    • 使用策略模式可以提高算法的保密性和安全性。

     策略模式的缺点如下:

    • 客户端必须知道所有的策略,并且自行决定使用哪一个策略类。
    • 代码中会产生非常多的策略类,增加了代码的维护难度。

    五、委派模式与策略模式综合应用

      委派模式:DispatcherServlet 根据url对应Controller 用的是if else, 应该将对应关系放入容器中,利用URL找到对应的Controller,这样做成策略模式。

  • 相关阅读:
    使用Fiddler抓取手机APP数据包--360WIFI
    mysql 查询数据库表信息,字段信息
    jQuery动态移除和绑定事件
    Topshelf+Quatz.Net的简单使用
    教你花30分钟时间搭建一个个人博客
    泛型接口的抗变和协变
    Action<T>和Func<T>
    DateTime和DateTimeOffset的区别
    Expression<Func<TObject, bool>>与Func<TObject, bool>的区别
    C#学习笔记(1) --简叙.net体系结构
  • 原文地址:https://www.cnblogs.com/xcgShare/p/12166125.html
Copyright © 2020-2023  润新知