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

一、策略模式的应用场景

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

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

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

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

  1. /**
  2. * 定义支付规范和支付逻辑
  3. */
  4. public abstract class Payment {
  5.  
  6. //支付类型
  7. public abstract String getName();
  8.  
  9. //查询余额
  10. protected abstract double queryBalance(String uid);
  11.  
  12. //扣款支付
  13. public PayState pay(String uid, double amount) {
  14. if (queryBalance(uid) < amount) {
  15. return new PayState(500, "支付失败", "余额不足");
  16. }
  17. return new PayState(200, "支付成功", "支付金额:" + amount);
  18. }
  19. }

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

  1. /**
  2. * 支付逻辑
  3. */
  4. public class PayState {
  5. private int code;
  6. private Object data;
  7. private String msg;
  8.  
  9. public PayState(int code, String msg, String data) {
  10. this.code = code;
  11. this.data = data;
  12. this.msg = msg;
  13. }
  14.  
  15. public String toString() {
  16. return ("支付状态:[" + code + "]," + msg + ",交易详情:" + data);
  17. }
  18. }

  定义两种支付方式:

  1. /**
  2. * 支付宝
  3. */
  4. public class AliPay extends Payment {
  5. @Override
  6. public String getName() {
  7. return "支付宝";
  8. }
  9.  
  10. @Override
  11. protected double queryBalance(String uid) {
  12. return 900;
  13. }
  14. }
  15.  
  16. /**
  17. * 微信支付
  18. */
  19. public class WechatPay extends Payment {
  20. @Override
  21. public String getName() {
  22. return "微信支付";
  23. }
  24.  
  25. @Override
  26. protected double queryBalance(String uid) {
  27. return 256;
  28. }
  29. }

  支付策略管理类

  1. /**
  2. * 支付策略管理类
  3. */
  4. public class PayStrategy {
  5. public static final String ALI_PAY = "AliPay";
  6. public static final String WECHAT_PAY = "WechatPay";
  7. public static final String DEFAULT_PAY = ALI_PAY;
  8.  
  9. private static Map<String, Payment> payStrategy = new HashMap<>();
  10.  
  11. static {
  12. payStrategy.put(ALI_PAY, new AliPay());
  13. payStrategy.put(WECHAT_PAY, new WechatPay());
  14. }
  15.  
  16. public static Payment get(String payKey) {
  17. if (!payStrategy.containsKey(payKey)) {
  18. return payStrategy.get(DEFAULT_PAY);
  19. }
  20. return payStrategy.get(payKey);
  21. }
  22. }

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

  1. /**
  2. * 订单类
  3. */
  4. public class Order {
  5. private String uid;
  6. private String orderId;
  7. private Double amount;
  8.  
  9. public Order(String uid, String orderId, Double amount) {
  10. this.uid = uid;
  11. this.orderId = orderId;
  12. this.amount = amount;
  13. }
  14.  
  15. //完美解决了switch的过程,不需要写switch和if...else if
  16. public PayState pay() {
  17. return pay(PayStrategy.DEFAULT_PAY);
  18. }
  19.  
  20. public PayState pay(String payKey) {
  21. Payment payment = PayStrategy.get(payKey);
  22. System.out.println("欢迎使用:" + payment.getName());
  23. System.out.println("本次交易金额为:" + amount + ",扣款中...");
  24. return payment.pay(uid, amount);
  25. }
  26. }

  测试类:

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

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

1.JDK中的应用

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

  1. public static <T> void parallelSort(T[] a, Comparator<? super T> cmp) {
  2. if (cmp == null)
  3. cmp = NaturalOrder.INSTANCE;
  4. int n = a.length, p, g;
  5. if (n <= MIN_ARRAY_SORT_GRAN ||
  6. (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
  7. TimSort.sort(a, 0, n, cmp, null, 0, 0);
  8. else
  9. new ArraysParallelSortHelpers.FJObject.Sorter<T>
  10. (null, a,
  11. (T[])Array.newInstance(a.getClass().getComponentType(), n),
  12. 0, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
  13. MIN_ARRAY_SORT_GRAN : g, cmp).invoke();
  14. }

  还有TreeMap类的构造方法:

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

2.Spring源码中的应用

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

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

四、策略模式的优缺点

 策略模式的优点如下:

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

 策略模式的缺点如下:

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

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

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

Spring中常见的设计模式——策略模式的更多相关文章

  1. Spring中常见的设计模式——代理模式

    一.代理模式的应用场景 生活中的中介,黄牛,等一系列帮助甲方做事的行为,都是代理模式的体现.代理模式(Proxy Pattern)是指为题对象提供一种代理,以控制对这个对象的访问.代理对象在客户端和目 ...

  2. Spring中常见的设计模式——委派模式

    一.委派模式的定义及应用场景 委派模式(Delegate Pattern)的基本作用是负责任务的调用和分配,跟代理模式很像,可以看做特殊情况下的静态的全权代理,但是代理模式注重过程,而委派模式注重结果 ...

  3. Spring中常见的设计模式——工厂模式

    一.简单工厂模式 简单工厂模式(Simple Factory Pattern)由一个工厂对象决定创建哪一种产品类的实例,简单工厂模式适用于工厂类负责创建对象较少的情况,且客户端只需要传入工厂类的参数, ...

  4. Spring中常见的设计模式——原型模式

    1.原型模式应用场景 当遇到大量耗费劳动力的 get,set赋值场景时,如下: public class SetGetParam { public void setParam(UserDto user ...

  5. Spring中常见的设计模式——模板模式

    一.模板模式的应用场景 模板模式又叫模板方法模式(Template Method Pattern),指定义一个算法的骨架,并允许自雷为一个或者多个步骤提供实现.模板模式使得子类可以在不改变算法结果的情 ...

  6. Spring中常见的设计模式——适配器模式

    一.适配器模式的应用场景 适配器模式(Adapter Pattern)是指将一个类的接口转换成用户期待的另一个接口,使原本接口不兼容的类可以一起工作,属于构造设计模式. 适配器适用于以下几种业务场景: ...

  7. 设计模式:JDK和Spring中常见的设计模式

    设计模式 总结 类 工厂模式 封装创建过程,只对结果负责 BeanFactory.Calender 单例模式 全局唯一 ApplicationContext.Calender 原型模式 多重影分身之术 ...

  8. Spring中常见的设计模式——单例模式

    一.单例模式的应用场景 单例模式(singleton Pattern)是指确保一个类在任何情况下都绝对只有一个实例,并提供一个全局访问点.J2EE中的ServletContext,ServletCon ...

  9. spring 中常用的设计模式

    一. Spring 中常见的设计模式 工厂模式 : BeanFactory 装饰器模式: BeanWrapper 代理模式: AopProxy 单例模式: ApplicationContext 委派模 ...

随机推荐

  1. oracle函数 power(x,y)

    [功能]返回x的y次幂 [参数]x,y 数字型表达式 [返回]数字 [示例] select power(2.5,2),power(1.5,0),power(20,-1) from dual; 返回:6 ...

  2. H3C 快速以太网和千兆以太网

  3. data-属性的作用

    data-用于存储页面或应用程序的私有自定义数据,赋予我们在所有HTML元素上嵌入自定义data属性的能力,存储的数据能被页面的JS利用,以创建更好的用户体验. <div id="bo ...

  4. mysql聚合函数和分组

    文章实例的数据表,来自上一篇博客<mysql简单查询>:http://blog.csdn.net/zuiwuyuan/article/details/39349611 一. 聚合函数 聚合 ...

  5. H3C CHAP验证配置示例一

  6. Study in JI During the Summer Vacation

    15/07/2019-21/07/2019 Task List: 1.uow homework including vocabulary and listening 2.ASL's dictation ...

  7. RBF神经网络通用函数 newrb, newrbe

      RBF神经网络通用函数 newrb, newrbe 1.newrb 其中P为输入向量,T为输出向量,GOAL为均方误差的目标,SPREED为径向基的扩展速度.返回值是一个构建好的网络,用newrb ...

  8. H3C PPP协议的组成

  9. echarts 图表自适应外部盒子大小

    项目中用到了echarts,由于页面是自适应的,还得兼容移动, 因此图表还需要根据盒子的大小来变化. 自适应窗口及盒子大小 页面中有一个[放大.缩小]功能,及全屏展示和预览图表 窗口自适应 let m ...

  10. 2019-9-2-Visual-Studio-自定义项目模板

    title author date CreateTime categories Visual Studio 自定义项目模板 lindexi 2019-09-02 12:57:38 +0800 2018 ...