一文简单全面了解策略模式的使用花几分钟轻松掌握一个知识点(代码片段)

码农飞哥 码农飞哥     2022-12-08     350

关键词:

您好,我是码农飞哥,感谢您阅读本文,欢迎一键三连哦

本文重点:介绍策略模式概念以及实际应用。
干货满满,建议收藏,需要用到时常看看。小伙伴们如有问题及需要,欢迎踊跃留言哦~ ~ ~。

在这里插入图片描述


在这里插入图片描述

问题需求(支付系统渠道商的选择问题)

聚合支付项目对接了三个渠道商,分别渠道商A,渠道商B,渠道商C,每个渠道商都有一套独立的对接文档(从商户入驻,到支付,到清算)。那么该如何实现这个功能呢?

问题解决

V1.0版本

V1.0版本就是直接梭哈,将所有的业务逻辑写在了客户端,客户端在调用的时候可以分别调用各个渠道商的商户入驻方法。

public class Client 
    public static void main(String[] args) 
        Client client = new Client();
        client.addCustomerA("商户1");
        client.addCustomerB("商户2");
        client.addCustomerC("商户3");
    

    public String addCustomerA(String customer) 
        System.out.println("渠道商A入驻"+customer+"成功");
        return "success";
    


    public String addCustomerB(String customer) 
        System.out.println("渠道商B入驻"+customer+"成功");
        return "success";
    

    public String addCustomerC(String customer) 
        System.out.println("渠道商C入驻"+customer+"成功");
        return "success";
    


上述代码把策略和调用都放在了客户端中,从中不难看出,如果要在增加一个渠道商的话,则必定要修改客户端 增加新渠道商的商户入驻方法。这样就会导致客户端变得十分臃肿复杂维护起来非常麻烦,同时也没有体现面向对象的设计思想,在生成中写出这样的代码怕是要被老板优化。 那么我们该如何优化呢?

v1.1版本

从面向对象的角度出发,每个渠道商抽象成一个具体的对象,用一个单独的类保存其属性和行为,同时公共行为(商户入驻的行为)则用一个接口来定义,每个渠道商的类分别实现这个接口。

  1. 定义公共的接口Income,该接口主要是规范了各个渠道商的行为,这里通过addCustomer方法定义了商户入驻的行为。
public interface Income 
    /**
     * 商户入驻
     * @return
     */
    String addCustomer(String customer);

  1. 定义各个渠道商的类,这里分别定义了MerchantAIncome,MerchantBIncome以及MerchantCIncome 三个渠道商的类,并且这三个类都实现了Income接口的addCustomer方法,实现商户入驻。
public class MerchantAIncome implements Income 
    @Override
    public String addCustomer(String customer) 
        System.out.println("渠道商A入驻"+customer+"成功");
        return "success";
    

  1. 定义环境类Context,这里的环境类主要的作用就是持有一个Income对象的引用,并且该Income对象所能操作的各种行为(即各种策略)。
public class Context 
    private Income income;

    public Context(Income income) 
        this.income = income;
    

    public String addCustomer(String customer) 
        return income.addCustomer(customer);
    

  1. 定义调用客户端
public class Client 
      public static void main(String[] args) 
        new Context(new MerchantAIncome()).addCustomer("商户1");
        new Context(new MerchantBIncome()).addCustomer("商户2");
        new Context(new MerchantCIncome()).addCustomer("商户3");
    

UML图

上述代码的UML图如下图所示:这里有三个主要的角色:

  1. 环境类Context
  2. 抽象的策略Income接口
  3. 具体的策略MerchantAIncome,MerchantBIncome以及MerchantCIncome这三个类。
    在这里插入图片描述
    如上图所示:每个渠道商的类都是实现了一个公共的接口,该接口定义了渠道商中各种行为,包括商户入驻等等。客户端判断当前使用的是哪个渠道商。然后,生成该渠道商的实例,接着调用该渠道商的相关方法。每个渠道商自身的变化不会影响到客户端。相比较于V1.0版本而言,代码逻辑简洁了很多,增加一个渠道商的话只需要再增加一个渠道商的类,并且在客户端中加上一个判断,符合开闭原则。这里就引出了本文将要介绍的模式----策略模式。

策略模式

定义

策略模式就是定义一系列的算法(对应本例中的一系列渠道商), 将每个算法封装到具有公共接口的一系列策略类中(对应到本例中就是将每个渠道商封装成一个单独的类,并且这些类实现一个公共的接口),从而使它们可以相互替换并且让算法可以在不影响客户端的情况下发生变化。

主要作用

从策略模式的定义中我们可以看出策略模式的主要作用就是将算法的责任和对象本身解耦,使得:

  1. 算法可以独立于客户端而变化(每个渠道商内部变化不影响客户端)
  2. 客户端可以根据外部条件而选择不同的策略来解决不同的问题。

优点

  1. 策略类之间可以自由切换
  2. 易于扩展,增加一个新的策略只需要添加一个具体的策略类即可,基本不需要改变原有的代码,符合“开闭原则”
  3. 消除了一些 if else条件语句

缺点

  1. 客户端必须知道所有的策略类,并自行决定使用哪个策略类。
  2. 策略模式将造成产生很多策略类,可以通过使用享元模式在一定程度上减少对象的数量。

策略模式与其它模式的比较

与状态模式的比较

策略模式的条件选择只执行一次,而状态模式是随着实例参数(对象实例的状态)的改变不停地更改执行模式。

与简单工厂模式的比较

工厂模式是创建型模式,它关注的是对象的创建,提供创建对象的接口,
策略模式是对象行为型模式,它关注的是行为和算法的封装。比如:出行方案中,策略模式是让你选择一种出行方式,而工厂模式是代替你构建具体的方案。

扩展延伸

v1.2版本

说完了策略模式,前面V1.1版本确实很好的运用到了策略模式,还是还不够,还是有点繁琐,客户端在调用的时候还是需要通过条件判断来决定使用哪种策略,这样还是没有干掉if和else,那么有没有什么方式可以干掉客户端的条件判断呢?答案是有的。我们可以通过枚举类来定义好各种渠道商的实例。
这里只需要新增一个枚举类

public enum MerchantIncomeEnum 

    MERCHANT_A("a", new MerchantAIncome()),
    MERCHANT_B("b", new MerchantBIncome()),
    MERCHANT_C("c", new MerchantCIncome()),;
    private String key;
    private Income income;

    MerchantIncomeEnum(String key, Income income) 
        this.key = key;
        this.income = income;
    
    
    public static Income getIncome(String key) 
        Map<String, Income> map = Arrays.stream(MerchantIncomeEnum.values()).collect(Collectors.toMap(p -> p.key, p -> p.income));
        return map.get(key);
    

修改环境类Context

public class Context 

    public String addCustomer(String key, String customer) 
        Income income = MerchantIncomeEnum.getIncome(key);
        return income.addCustomer(customer);
    

这样客户端在调用的时候只需要传入指定渠道商的Key就可以调用指定渠道商的方法。

总结

本文由一个实际应用场景出发,引出了策略模式:策略模式主要解决的问题是如何将对象和算法分开,使得算法可以独立于使用它的客户端而变化。它的优点是易于扩展,策略类之间可以自由的切换。缺点是客户端在调用的时候必须要知道所有的策略类,并自行决定使用哪个策略类。同时策略模式会产生很多策略类。策略模式的适用于有一系列算法或者策略的场景下,比如:商场的各种折扣算法,出行的各种方案等等。

设计模式-适配器模式(go语言描写叙述)

...一篇博客设计模式-策略模式(Go语言描写叙述)中我们用最简单的代码用go语言描写叙述了设计模式中的策略模式,用最简单的实例来描写叙述相信能够让刚開始学习的人能够非常轻松的掌握各种设计模式。继上篇博客,我们接着... 查看详情

教你轻松掌握数据仓库的规划和构建策略

...库的开发规划过程实际上是一个用户和设计人员对其不断了解、熟悉和完善的过程。数据仓库的开发应用规划是开发数据仓库的首要任务。只有制定了正确的数据仓库规划,才能使组织主要力量有序地实现数据仓库的开发应用。... 查看详情

三分钟轻松了解spring框架基础知识

...小编会带着大家一步步了解Spring框架。struts:web层,比较简单(ValueStack值栈,拦截器); hibernate:dao层,知识点杂; spring:service层,重要,讲多少用多少。脑海中的架构:一、s 查看详情

一文带你轻松掌握多种编程范式(代码片段)

一文带你轻松掌握多种编程范式前言结构化程序的设计基于对象的程序设计面向对象的程序设计基于接口的程序设计基于接口编程的模板实现前言 编程范式有多种,主要有结构化的程序设计思想、基于对象的程序设计思想... 查看详情

手把手带你使用策略模式实现表单校验(代码片段)

策略模式文章目录策略模式前言一了解策略模式二实现表单校验前言你的项目有哪些亮点?你对设计模式是否了解?这些都是面试官常问的问题,这两个问题都可以通过本文解决。毋庸置疑,使用策略模式实现表... 查看详情

一文带你全面了解rxjava

工作需要,刚好在学习RxJava网络请求框架,网上搜了一些关于RxJava的教程,但都并不是很好理解,所幸最后找到了几篇有助于初学者了解RxJava的文章,于是结合自己的理解,重新整理成一篇发给大家,希望通过我的咀嚼,能够帮... 查看详情

15分钟掌握elasticsearch8大核心概念与基础用法

...概念和安装、用法,15分钟实现入门并且掌握Elasticsearch的简单使用。Elasticsearch提供一整套的RestAPI用以支持各种索引、文档、搜索等操作。这里我们简单以索引的创建、查询和删除为例子来了解如何操作Elasticsearch。Elasticsearch中... 查看详情

mysql性能调优,必须掌握这一个工具!!!(1分钟系列)

《数据库允许空值(null),往往是悲剧的开始》一文通过explain来分析SQL的执行计划,来分析null对索引命中情况的影响。explain是MySQL性能调优过程中必须掌握的工具,今天花1分钟简单说下,explain结果中常见的type结... 查看详情

mysql性能调优,必须掌握这一个工具!!!(1分钟系列)

《数据库允许空值(null),往往是悲剧的开始》一文通过explain来分析SQL的执行计划,来分析null对索引命中情况的影响。explain是MySQL性能调优过程中必须掌握的工具,今天花1分钟简单说下,explain结果中常见的type结... 查看详情

一文搞懂│工厂模式单例模式策略模式适配器模式观察者模式的原理和使用(代码片段)

✨目录🎈工厂模式🎈单例模式🎈策略模式🎈适配器模式🎈观察者模式🎈工厂模式工厂模式的原理作用:就是你只要传你需要的类进去,你就能得到他的实例化对象其实工厂就是帮你实例化你所... 查看详情

一文搞懂│工厂模式单例模式策略模式适配器模式观察者模式的原理和使用(代码片段)

✨目录🎈工厂模式🎈单例模式🎈策略模式🎈适配器模式🎈观察者模式🎈工厂模式工厂模式的原理作用:就是你只要传你需要的类进去,你就能得到他的实例化对象其实工厂就是帮你实例化你所... 查看详情

策略模式

策略模式,需要我们结合简单工厂模式,更高级地用法可能需要我们掌握Java反射机制。简单工厂模式我们在最早的时候介绍,我们也谈到了一点Java的反射机制。借着学习策略模式的机会,我们顺便复习一下简单工厂模式和反射... 查看详情

设计模式那点事--策略模式

...法。    样例:    一个鲜活简单的样例总能让人轻松地理解晦涩的概念。我们来看看一 查看详情

一分钟轻松掌握!java高级数据结构--原生bitset源码刨析

文章目录为啥要肝Java原生BitSetBitSet介绍BitSet使用Set偷窥真相的入口Set源码计算word数组下标数组words[wordIndex]元素位操作Go重写Java原生包BitSetQ&A附录为啥要肝Java原生BitSet  今天,来聊下关于java.util包中的BitSet。为什么突然聊... 查看详情

轻松掌握docker使用-进阶操作(代码片段)

...此每一条指令的内容,就是描述该层应当如何构建。简单来说就是,一个形容如何构建镜像的文本文件,而文件中包含了一条条的指令,通过指令告诉docker想构建出怎样的镜像。Dockerfile“初使用”这里我们自定义... 查看详情

爬虫好学么?

...人工智能、数据分析、深度学习来讲,Python爬虫还是比较简单的。想要从事爬虫工作,需要掌握以下知识:学习Python基础知识并实现基本的爬虫过程一般获取数据的过程都是按照发送请求-获得页面反馈-解析并且存储数据这三个... 查看详情

一文了解数据库操作--mysql(25分钟)(代码片段)

🏆今日学习目标:🍀学习了解数据库操作✅创作者:贤鱼⏰预计时间:25分钟🎉个人主页:贤鱼的个人主页🔥专栏系列:网络安全mysql数据库数据库简述数据库sql和nosql常见关系型数据库sql语... 查看详情

一文了解数据库操作--mysql(25分钟)(代码片段)

🏆今日学习目标:🍀学习了解数据库操作✅创作者:贤鱼⏰预计时间:25分钟🎉个人主页:贤鱼的个人主页🔥专栏系列:网络安全mysql数据库数据库简述数据库sql和nosql常见关系型数据库sql语... 查看详情