还在用if-else? 用策略模式干掉它

策略模式(Strategy Pattern)

策略模式是一种行为设计模式,它将一组行为转换为对象, 并使其在原始上下文对象内部能够相互替换。大白话就是比如我写一个登录业务,目前需要满足能通过系统内、微信等平台进行登录,未来还有可能引入其他的平台,这个时候就可以采用策略模式,来让不同的平台的登录都有对应的策略路径。

在这里插入图片描述

此外对于不同类型的交易方式(信用卡、支付宝、微信),生成唯一ID的策略(UUID、雪花算法、Leaf算法)等,我们都可以先用策略模式对其进行行为包装,然后提供给外界进行调用。

一、 策略模式介绍

在策略模式中,主要有两个部分:

  • 表示各种策略的对象Strategy
  • 行为随着策略对象改变而改变的原始对象Context,它主要用于分发不同策略对象

注意,如果一个系统中的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。下面来看看对应的UML结构图:

image-20220413094838056

  • Stategy:抽象策略结构,定义不同策略需要执行的统一步骤和方法
  • ConcreteStrategy1、ConcreteStrategy2:实现抽象策略定义的接口,提供具体的算法实现
  • Context:上下文类,是外界获取不同策略的接口

二、策略模式应用

2.1 Java Comparator中的策略模式

java.util.comparator 中,comparator作为比较的接口,可以实现具体的比较策略。而java.util.Collections 中的sort(List<T> list, Comparator<? super T> c) 作为context类,执行不同的比较逻辑
在这里插入图片描述

可以做一个排序的demo来演示:

 public static void main(String[] args) {
        ArrayList<Integer> integers = new ArrayList<>();
        integers.add(1);
        integers.add(3);
        integers.add(5);
        integers.add(4);
        integers.add(2);
        for (Integer integer : integers) {
            System.out.print(integer);
        }
        System.out.println("顺序后~");
        Collections.sort(integers,new AscComparator());
        for (Integer integer : integers) {
            System.out.print(integer);
        }
        System.out.println("逆序后~");
        Collections.sort(integers,new DescComparator());
        for (Integer integer : integers) {
            System.out.print(integer);
        }
        InstantiationStrategy

    }

    static class DescComparator implements Comparator<Integer> {
        @Override
        public int compare(Integer o1, Integer o2) {
            return o2 - o1;
        }
    }
    static class AscComparator implements Comparator<Integer> {
        @Override
        public int compare(Integer o1, Integer o2) {
            return o1 - o2;
        }
    }

最后输出:

13542顺序后~
54321逆序后~
12345

2.2 Spring Bean实例化中的策略模式

其中InstantiationStrategy 作为实例化策略接口,AbstractAutowireCapableBeanFactory 作为上下文,创建策略并调用

在这里插入图片描述

三、 策略模式实战

3.1 生成不同的ID策略

就拿生成唯一ID业务来举例子,比如在雪花算法提出之前,我们一般使用的是UUID 来确认唯一ID。但是如果需要有序的生成ID,这个时候就要考虑一下其他的生成方法,比如雪花、Leaf等算法了。

可能刚开始我们是直接写一个类,在类里面调用UUID算法来生成,但是需要调用其他方法时,我们就必须在这个类里面用if-else等逻辑判断,然后再转换成另外的算法中。这样的做法和前面提到的工厂模式一样,会提高类之间的耦合度。所以我们可以使用策略模式将这些策略抽离出来,单独实现,防止后期若需要扩展带来的混乱。

首先,定义一个ID生成的接口IIdGenerator

public interface IIdGenerator {
    /**
     * 获取ID, 目前有三种实现方式
     * 1.雪花算法,主要用于生成单号
     * 2.日期算法,用于生成活动标号类,特性是生成数字串较短,但是指定时间内不能生成太多
     * 3.随机算法,用于生成策略ID
     * @return ID 返回ID
     */
    long nextId();
}

让不同生成ID策略实现该接口:

下面是雪花算法的具体实现 :

public class SnowFlake implements IIdGenerator {

    private Snowflake snowflake;

    @PostConstruct
    public void init() {
        //总共有5位,部署0~32台机器
        long workerId;
        try {
            workerId = NetUtil.ipv4ToLong(NetUtil.getLocalhostStr());
        } catch (Exception e) {
            workerId = NetUtil.getLocalhostStr().hashCode();
        }

        workerId = workerId >> 16 & 31;

        long dataCenterId = 1L;
        snowflake = IdUtil.createSnowflake(workerId, dataCenterId);
    }

    @Override
    public long nextId() {
        return snowflake.nextId();
    }
}

其次还要定义一个ID策略控制类IdContext ,通过外部不同的策略,利用统一的方法执行ID策略计算,如下所示:

@Configuration
public class IdContext {

    @Bean
    public Map<Constants.Ids, IIdGenerator> idGenerator(SnowFlake snowFlake, ShortCode shortCode, RandomNumeric randomNumeric) {
        Map<Constants.Ids, IIdGenerator> idGeneratorMap = new HashMap<>(8);
        idGeneratorMap.put(Constants.Ids.SnowFlake, snowFlake);
        idGeneratorMap.put(Constants.Ids.ShortCode, shortCode);
        idGeneratorMap.put(Constants.Ids.RandomNumeric, randomNumeric);
        return idGeneratorMap;
    }
}

所以在最后测试时,直接调用idGeneratorMap就可以实现不同策略服务的调用:

 @Test
 public void init() {
     logger.info("雪花算法策略,生成ID: {}", idGeneratorMap.get(Constants.Ids.SnowFlake).nextId());
     logger.info("日期算法策略,生成ID: {}", idGeneratorMap.get(Constants.Ids.ShortCode).nextId());
     logger.info("随机算法策略,生成ID: {}", idGeneratorMap.get(Constants.Ids.RandomNumeric).nextId());
 }
  1. 2 实现不同平台登录系统

正如前言提到的,在同样的登录过程中,需要实现不同平台的登录策略,这里就单列出微信登录系统的实现逻辑来展示策略模式:

  1. 登录接口

该部分提供给前端进行调用,通过前台传递不同的平台参数,来执行不同的登录策略:

public Result<JSONObject> login(@RequestBody LoginRequestModel loginRequest) {
    Result<JSONObject> result = new Result<JSONObject>();
    if (loginRequest.getThirdPlatform() == null) {
        result.error500("找不到该平台,请配置后再登录!");
        return result;
    } else {
        LoginStrategy loginStrategy = loginStrategyContext.getLoginStrategy(loginRequest.getThirdPlatform());
    	result = loginStrategy.login(loginRequest);
    	return result;
    }
}
  1. 登录策略context

该部分主要通过创建登录策略来进行调用, 这里是利用spring来将不同策略对象提前注入,方便管理和调用

@Component
public class LoginStrategyContext{

    private Map<String, LoginStrategy> strategies = new ConcurrentHashMap<>();

    /**
     * 将所有策略注入springBean中
     * @param strategies
     */
    public LoginStrategyContext(Map<String, LoginStrategy> strategies) {
        strategies.forEach(this.strategies::put);
    }
    public LoginStrategy getLoginStrategy(String strategyName) {
        LoginStrategy loginStrategy = strategies.get(strategyName);
        return loginStrategy;
    }

}
  1. 策略接口和具体实现

该部分完成登录策略接口和具体的登录实现策略

public interface LoginStrategy {
    /**
     * 处理具体登录逻辑
     * @return
     */
    Result<JSONObject> login(LoginRequestModel loginRequest);
}
public class WeChatLoginStrategy implements LoginStrategy {
    @Override
    public Result<JSONObject> login(LoginRequestModel loginRequest) {
        //处理具体的登录逻辑
    }
}

以上就是关于策略设计模式的内容,其实在日常业务逻辑中对于设计模式的使用,并不是非得一定要代码中有设计模式才行,简单的逻辑就用if-else即可。如果有复杂的业务逻辑,而且也符合对应的设计模式,这样使用模式才能真正提高代码的逻辑性和可扩展性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/294186.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

前端页面锚点跳转

一&#xff0c;页面 二&#xff0c;获取需要跳转的标签class或者id 三&#xff0c;调用跳转方法 如果你的标签有唯一的ID&#xff0c;那么用getElementById方法更好 点击即可跳转锚点

在 Walrus 上轻松集成 OpenTofu

OpenTofu 是什么&#xff1f; OpenTofu 是一个开源的基础设施即代码&#xff08;IaC&#xff09;框架&#xff0c;被提出作为 Terraform 的替代方案&#xff0c;并由 Linux 基金会管理。OpenTofu 的问世为应对 HashiCorp 将 Terraform 的许可证从 Mozilla Public License v2.0…

内网穿透的应用-使用Docker本地部署可编辑导航页结合内网穿透实现远程访问

文章目录 1. 使用Docker搜索镜像2. 下载镜像3. 查看镜像4. 启动容器5. 浏览器访问6. 远程访问6.1 内网穿透工具安装6.2 创建远程连接公网地址6.3 使用固定二级子域名地址远程访问 今天和大家分享如何使用Docker本地部署一个开源的简约风格网址导航页&#xff0c;支持五种搜索引…

GeoServe本地部署结合内网穿透实现远程访问Web管理界面

文章目录 前言1.安装GeoServer2. windows 安装 cpolar3. 创建公网访问地址4. 公网访问Geo Servcer服务5. 固定公网HTTP地址 前言 GeoServer是OGC Web服务器规范的J2EE实现&#xff0c;利用GeoServer可以方便地发布地图数据&#xff0c;允许用户对要素数据进行更新、删除、插入…

域名流量被劫持怎么办?如何避免域名流量劫持?

随着互联网不断发展&#xff0c;流量成为线上世界的巨大财富。然而一种叫做域名流量劫持的网络攻击&#xff0c;将会在不经授权的情况下控制或重定向一个域名的DNS记录&#xff0c;导致用户在访问一个网站时&#xff0c;被引导到另一个不相关的网站&#xff0c;从而劫持走原网站…

查询slurm集群各个节点的运行情况

引言 slurm系统是一个集群&#xff0c;它原生的使用方式可以参考之前写的《slurm初识》和《slurm快速入门》。有时候我们想知道我们能申请哪些节点&#xff0c;以及各个节点的使用情况。 原生的指令大概有这两个&#xff0c;一个是使用squeue的方式列举出当前的工作列表。 …

Windows通过注册表修改socket缓冲区大小的方法

在 Windows 通过修改注册表来更改 UDP 缓冲区的大小&#xff0c;按照以下步骤进行操作&#xff1a; 打开注册表编辑器&#xff1a;按下 Win R 键&#xff0c;然后输入 "regedit" 并点击 "确定"。 导航到以下路径&#xff1a;HKEY_LOCAL_MACHINE\System\C…

每日汇评:今天市场重点都转移到美国非农就业数据

周四美元走势摇摆不定&#xff1b; 到目前为止&#xff0c;欧元兑美元仍受到1.0900区域的支撑&#xff1b; 市场的下一个风险事件是美国就业数据的发布&#xff1b; 欧元兑美元在周四成功恢复了上涨动力&#xff0c;并短暂重返1.0970区间&#xff0c;在连续四个交易日的空头主导…

微服务应用可观测性解决方案介绍

目录 一、可观测性出现背景 二、什么是可观测性&#xff08;Observability&#xff09; 2.1 可观测性的不同解析 2.1.1 百度维基解析 2.1.2 IBM解析 2.1.3 CNCF&#xff08;云原生计算机基金会&#xff09;组织解析 2.1.4 我的个人理解 2.2 可观测性和监控的区别与联系 …

C++完成使用map Update数据 非二进制

1、在LXMysql.h和LXMysql.cpp分别定义和编写关于pin语句的代码 //获取更新数据的sql语句 where语句中用户要包含where 更新std::string GetUpdatesql(XDATA kv, std::string table, std::string where); std::string LXMysql::GetUpdatesql(XDATA kv, std::string table, std…

OpenHarmony内存泄漏指南 - 解决问题(综合)

本系列文章旨在提供定位与解决OpenHarmony应用与子系统内存泄露的常见手段与思路&#xff0c;将会分成几个部分来讲解。首先我们需要掌握发现内存泄漏问题的工具与方法&#xff0c;以及判断是否可能存在泄漏。接着需要掌握定位泄漏问题的工具&#xff0c;以及抓取trace、分析tr…

我们正迎来计算基因的巨大变革,即将到来的不仅是量子技术——

计算机是围绕逻辑构建的&#xff1a;利用电路执行数学运算。逻辑是围绕诸如加法器——这种将两个数字相加的基本电路&#xff0c;而构建的。 今天的微处理器和计算机历史初期的所有微处理器都是如此。这可以追溯到算盘&#xff0c;在某些基本层面上&#xff0c;这和你闪亮的游戏…

前端根据URL地址实现下载(txt,图片,word,xlsx,ppt)

前端根据URL地址实现下载&#xff08;txt&#xff0c;图片&#xff0c;word&#xff0c;xlsx&#xff0c;ppt&#xff09; 一、对于txt,图片类的二、对于word&#xff0c;xlsx&#xff0c;ppt类的1.a标签可以实现下载2. window.open&#xff08;&#xff09; 一、对于txt,图片类…

软件推荐:MobaXterm

介绍 MobaXterm 是远程计算的终极工具箱&#xff0c;它提供了几乎所有重要的远程网络工具&#xff0c;SSH、RDP、FTP、VNC&#xff0c;只要你能想到的&#xff0c;都可以在MobaXterm中找到。除了海量协议外&#xff0c;MobaXterm 还支持安装额外的插件来扩展其功能。 软件官网…

技术查漏补缺(1)Logback

一、下定义&#xff1a;Logback是一个开源的日志组件 二、Logback的maven <!--这个依赖直接包含了 logback-core 以及 slf4j-api的依赖--> <dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><v…

MySQL-数据库概述

数据库相关概念&#xff1a; 数据库(DateBase)简称DB,就是一个存储数据的仓库&#xff0c;数据有组织的进行存储。 数据库分为关系型数据库简称RDBMS和非关系型数据库 关系型数据库简称RDBMS:建立在关系模型的基础上&#xff0c;由多张相互连接的二维表组成的数据库.简单来说…

D6208双向直流马达驱动芯片 用于IPC产品,可兼容BA6208,噪声低 ,工作电源电压范围宽。

D6208 是一块单片双向马达驱动电路&#xff0c;它使用TTL电平的逻辑信号就能控制卡式录音机和其它电子设备中的双向马达。该电路由一个逻辑部分和一个功率输出部分组成。逻辑部分控制马达正、反转向及制动&#xff0c;功率输出部分根据逻辑控制能提供100mA&#xff08;典型值&a…

处理数组,将一维转二维

实现金刚区可滑动效果 由于后端返回的数据是 不符合项目需求&#xff0c;所以需要将它转为为二位数组 // 转为二维数组convertOneDimArray() {let arr [integral, kefu-ermai, coupon, gift, scan, pause-circle, wifi, email, integral,kefu-ermai, coupon, gift, scan, pau…

前端知识体系思维导图

绝大部分分类方法、专业术语&#xff0c;出自专业书籍&#xff0c;如《JavaScript 高级程序设计&#xff08;第 4 版&#xff09;》、《JavaScript 权威指南&#xff08;第 7 版&#xff09;》《CSS 权威指南&#xff08;第四版&#xff09;》、《HTML5 权威指南》、《计算机网…

Postman的七种断言方法+超时设置!

超时的设置 Settings->General->Request Timeout in ms(0 for infinity)&#xff1a;设置请求超时的时间,默认为0 1.postman断言介绍 postman在发送请求后&#xff0c;需要对返回的结果做判断&#xff0c;验证是否符合预期&#xff0c;如状态码、响应头、响应正文等信息…