策略模式【结合Spring框架实践】

news2024/11/25 13:00:40

Hello!~大家好啊,很高兴我们又见面了,今天我们一起学习设计模式–【策略模式】

初次对此模式不懂的,或者想偷懒的,我强烈建议大家跟着我的一起把概念和代码一起敲一遍!~为啥子??因为我就是这样学会的,哈哈哈!

1.首先我们看下此模式的整体UML

selector:选择器又叫做上下文context,【作用】通过不同的标识从而获取对应的策略实例(这是很关键的一个点,你细品~)

抽象策略: 如图所示,这是策略模式的顶层接口【就相当于领导~干运筹帷幄的】

策略实例 n:封装不同算法业务的实例对象,【就是特么真正干活的~!比如俺们码农】

在这里插入图片描述

2.案例实现

我们一个实际的案例进行实操,掌握这看起来高大上的策略模式,也是后面若你要面试,也能吹牛逼啊~

案例:

比如我们要统计餐厅的人流量数据做统计,统计的时间维度:一周和一个月,我们用策略模式咋实现呢? 我们往下看

实现需求分析:

在这里插入图片描述

  1. 前置设计:
    1. 我们定义常量标识策略的类型,
    2. 使用者调用时可通过常量获取对应的策略实例
  2. 策略设计
    1. 策略实例: 创建两个Bean实例: 周维度 &&月维度,并实现其中对应的算法和业务
    2. 抽象策略:通常我们定义一个通用的接口或者抽象方法,为啥???为了让外部能够访问啊!否则不是闭关锁国了嘛!~~
  3. 选择器设计: 这块就是挺重要的啦,我们通常采用MAP来存储数据,这样调用者就可以通过策略标识获取对应的策略实例

注意:

对于第三点可以是一道面试题:请问你怎么将策略的Bean注入到MAP中的?(不看答案,别心里好家伙,思考思考~哈哈)

也许你的第一反应:

我就直接将Bean对应的Class写死在``MAP中,然后通过applicationContext.getBaen()`获取其实例,这是最简单粗暴的!(也一看就是**菜鸡写法**哈哈哈)

若是这样回答,面试官肯定会问,这个通过写死的方法,那么下次我想增加其他维度的那不是要再次往Map中再添加,这麻烦先不说,也不符合开闭原则啊!~

你尴尬的扣了扣脚,微笑回答到:

是的,这是我一开始使用的,当时业务量不大,只考虑上面的两种情况,我就直接使用采取这种直接写死法,

但后面随着业务线的拓展,我也发现此中写法的弊端:

我的改进措施:(在Springboot的环境中)

1.通过解析注解来实现,给每个策略实例打上一个注解,我们业务是以周和月为维度进行常量标识的

2.过程: 在Springboot启动时,通过扩展点扫描抽象策略,获取它的策略实例

3.然后解析注解,放入MAP

这种就不用对原先代码就行逻辑代码改动,既符合开闭原则,又回到了面试官,爽哉!~

说了这么多,那关于代码我们怎么实现呢?–>耐心点,我们一起往下看

代码实现

1.抽象策略

package org.boyunv.strategy_pattern.handler;

/**
 * <p>
 * 描述:  抽象策略    <br>
 * <p>
 * 需求信息: 【需求ID与需求标题】【客户名称】 <br>
 *
 * @author aristo
 * @date 2024/1/23 19:07
 */
public interface TimeDimensionBaseHandlerInterface {
    //此方法是留给不同策略实体实现不同策略的方法实现
    void  statistic();
}

2.【策略实体】

这里我们注册组件直接采用Spring框架的组件@Component进行注册即可

1.周统计维度

package org.boyunv.strategy_pattern.handler;

import org.springframework.stereotype.Component;

/**
 * <p>
 * 描述:  策略实体: 周统计维度$      <br>
 * <p>
 * 需求信息: 【需求ID与需求标题】【客户名称】 <br>
 *
 * @author aristo
 * @date 2024/1/23 19:12
 */
@Component("week")
public class StatisticByWeekHandler implements TimeDimensionBaseHandlerInterface{
    @Override
    public void statistic() {
        //具体实现
        System.out.println("通过周统计维度实现统计数据");
    }
}

2.月统计维度

package org.boyunv.strategy_pattern.handler;

import org.springframework.stereotype.Component;

/**
 * <p>
 * 描述:  策略实体: 月统计维度$      <br>
 * <p>
 * 需求信息: 【需求ID与需求标题】【客户名称】 <br>
 *
 * @author aristo
 * @date 2024/1/23 19:12
 */
@Component("month")
public class StatisticByMonthHandler implements TimeDimensionBaseHandlerInterface{

    @Override
    public void statistic() {
        System.out.println("通过月统计维度实现统计数据");
    }
}

3.选择器【Inevitable!】

看如下的代码,我们会发现他同样是个组件,@Component

@Resource:将我们注册的weekmonth组件注册进入MAP

package org.boyunv.strategy_pattern.selector;

import org.boyunv.strategy_pattern.handler.TimeDimensionBaseHandlerInterface;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Map;

/**
 * 描述:  选择器,核心重点$      <br>
 * 需求信息: 【需求ID与需求标题】【客户名称】 <br>
 * @date 2024/1/23 19:26
 */
@Component
public class StatisticSelector {
    //这就和我们上面的所说的:定义Map,并通过@Resource注解完成我们刚才week和month的组件注入(很关键的一步哦!~)
    @Resource
    private Map<String, TimeDimensionBaseHandlerInterface> selectorMap;

    //下面根据类型选择策略
    public TimeDimensionBaseHandlerInterface select(String type){
        return selectorMap.get(type);
    }
}

4.我们进行测试

package org.boyunv.strategy_pattern.selector;

import org.boyunv.strategy_pattern.handler.TimeDimensionBaseHandlerInterface;
import org.junit.Test;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Map;

/**
 * 描述:  选择器,核心重点$      <br>
 * 需求信息: 【需求ID与需求标题】【客户名称】 <br>
 * @date 2024/1/23 19:26
 */
@Component
public class StatisticSelector {
    //这就和我们上面的所说的:定义Map,并通过@Resource注解完成我们刚才week和month的组件注入(很关键的一步哦!~)
    @Resource
    private Map<String, TimeDimensionBaseHandlerInterface> selectorMap;

    //下面根据类型选择策略
    public TimeDimensionBaseHandlerInterface select(String type){
        return selectorMap.get(type);
    }

    public  void doInvoke(String type){
        TimeDimensionBaseHandlerInterface handler=select(type);
        handler.doStatistic();
    }
    @Test
    public void invoke(){
        this.doInvoke("week");
        this.doInvoke("month");
    }
}

完结:

通过上面的运行步骤,我们最中实现策略模式的周和月的策略实现

这里面的核心点,再次提醒下:

通过Spring获取接口的实现,并解析实现类上的注解的方式,可以在程序启动时动态的将策略注入到一个Map中,作为策略的容器。

使用时传入标识符(就是常量)就可以获取到对应的策略执行了。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第五课:MindSpore自动并行

文章目录 第五课&#xff1a;MindSpore自动并行1、学习总结&#xff1a;数据并行模型并行MindSpore算子级并行算子级并行示例 流水线并行GPipe和Micro batch1F1B流水线并行示例 内存优化重计算优化器并行 MindSpore分布式并行模式课程ppt及代码地址 2、学习心得&#xff1a;3、…

Android 内存优化 内存泄漏

内存抖动 内存抖动是由于短时间内有大量对象进出新生区导致的&#xff0c;内存忽高忽低&#xff0c;有短时间内快速上升和下落的趋势&#xff0c;分析图呈锯齿状。 它伴随着频繁的GC&#xff0c;GC 会大量占用 UI 线程和CPU 资源&#xff0c;会导致APP 整体卡顿&#xff0c;甚…

Jupyter Notebook安装使用教程

Jupyter Notebook 是一个基于网页的交互式计算环境&#xff0c;允许你创建和共享包含代码、文本说明、图表和可视化结果的文档。它支持多种编程语言&#xff0c;包括 Python、R、Julia 等。其应用场景非常广泛&#xff0c;特别适用于数据科学、机器学习和教育领域。它可以用于数…

安装ROS2-ubuntu

相较于ROS1&#xff0c;ROS2在设计之初就考虑了在产品环境下⾯临的⼀些挑战&#xff0c;具体来说&#xff0c;ROS2采⽤&#xff08;或者计划采⽤&#xff09;以下策略以提升其在产品环境的适⽤度&#xff1a; ⽀持多机器⼈ 对⼩型嵌⼊式设备和微控制器的⽀持 实时系统&am…

《WebKit 技术内幕》学习之四(1): 资源加载和网络栈

第四章 资源加载和网络栈 使用网络栈来下载网页和网页资源是渲染引擎工作的第一步 1.WebKit 资源加载机制 1.1 资源 网页本身就是一种资源、网页还需要依赖很多其他的资源(图片、视频) &#xff08;1&#xff09;HTML 支持的资源主要包括以下几种类型&#xff1a; HTML 页…

Linux Shell alias的简单用法:给shell起别名

alias&#xff1a;显示该用户所有起过别名的命令 alias lla‘ls -al’&#xff1a;给ls -al起别名为lla unalias lla&#xff1a;取消lla的别名 1、该命令所有的操作只对个人用户生效&#xff0c;给普通用户起的别名在root用户下不生效&#xff0c;只有回到普通用户才生效。 2…

JOSEF约瑟 中间继电器JZ14-44Z/4 不带外罩和接线座

系列型号 JZ14-014Z/0中间继电器;JZ14-014Z/1中间继电器; JZ14-014Z/2中间继电器;JZ14-014Z/4中间继电器; JZ14-014J/0中间继电器;JZ14-014J/1中间继电器; JZ14-014J/2中间继电器;JZ14-014J/3中间继电器; JZ14-014J/4中间继电器;JZ14-140Z/0中间继电器; JZ14-140Z/1中间继…

[UI5 常用控件] 01.Text

文章目录 前言1. 普通文本2. 长文本&#xff1a;3. 设置最大显示行数 ( maxLines3 )4. 单行显示 ( wrappingfalse )5. 显示空白符 ( renderWhitespacetrue )6. 使用 - 连接单词:只适用于英文 ( wrappingTypeHyphenated )7. 空白时使用 - 代替 ( emptyIndicatorModeOn )8. JSON数…

Linux之权限(内容详细,细节满满)

个人主页&#xff1a;点我进入主页 专栏分类&#xff1a;C语言初阶 C语言程序设计————KTV C语言小游戏 C语言进阶 C语言刷题 数据结构初阶 Linux 欢迎大家点赞&#xff0c;评论&#xff0c;收藏。 一起努力 目录 一.前言 二.权限修改的两种方法 …

爬虫入门到精通_基础篇1(爬虫基本原理讲解, Urllib库基本使用)

01 爬虫基本原理讲解 1.什么是爬虫:请求网站并提取数据的自动化程序 2.爬虫基本流程&#xff1a; 发起请求&#xff1a;通过HTTP库向目标站点发起请求&#xff0c;即发送一个Request,请求可以包含额外的headers等信息&#xff0c;等待服务器响应。获取响应内容&#xff1a;如…

python实现归并排序

归并排序 归并排序是采用分治法的一个非常典型的应用。归并排序的思想就是先递归分解数组&#xff0c;拍好各数组的顺序&#xff0c;再合并数组。 将数组分解最小之后&#xff0c;然后合并两个有序数组&#xff0c;基本思路是比较两个数组的最前面的数&#xff0c;谁小就先取…

银行常用操作指引:浦发

文章目录 引言浦发2.1 设置查询密码2.2 微信公众号绑定2.3 查询卡转账额度II 其他银行常用操作see also引言 浦发 2.1 设置查询密码 2.2 微信公众号绑定 入口:点击菜单的微信通知 用途:查询余额和明细 口令:解除绑定 2.3 查询卡转账额度 II 其他银行常用操作

06 栈

目录 1.栈 2.实现 3.OJ题 1. 栈 1. 栈的概念和结构 栈: 这一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out&…

OSS存储引擎如何使用以及如何添加图片【建议收藏】

Aliyun OSS对象存储&#xff0c;可以用来做文件服务器&#xff0c;存放一些文件&#xff0c;图片等资源&#xff0c;那么我们使用OSS&#xff0c;需要经历以下步骤&#xff1a; 这里就从如何开通OSS服务开始进行&#xff0c;到如何上传一个资源文件到OSS结束。 1、阿里云注册 …

最新AI系统ChatGPT网站系统源码,支持AI绘画,GPT语音对话,ChatFile文档对话总结,DALL-E3文生图,MJ绘画局部编辑重绘

一、前言 SparkAi创作系统是基于ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;那么如何搭建部署AI创作ChatGPT&#xff1f;小编这里写一个详细图文教程吧。已支持GPT…

Python中==和is有什么区别

是比较两个对象的内容是否相等&#xff0c;即两个对象的“值”是否相等&#xff0c;不管两者在内存中的引用地址是否一样。 is 比较的是两个实例对象是不是完全相同&#xff0c;它们是不是同一个对象&#xff0c;占用的内存地址是否相同。即is比较两个条件&#xff1a;1.内容相…

LeetCode670.最大交换

我真的怀疑他是不是难度等级评错了&#xff0c;因为感觉没到中级&#xff0c;总之先看题吧 给定一个非负整数&#xff0c;你至多可以交换一次数字中的任意两位。返回你能得到的最大值。 示例 1 : 输入: 2736 输出: 7236 解释: 交换数字2和数字7。示例 2 : 输入: 9973 输出:…

数字拆分--完全背包问题

一、题目 https://acm.ecnu.edu.cn/problem/3034/ 二、思路 本来算法就很弱&#xff0c;加上很久没刷题&#xff0c;做这道题真的是一言难尽~ 一开始我以为是找规律写递推式&#xff0c;写到f(9)的时候就觉得不对劲&#xff0c;又想了一会&#xff0c;还是没想到&#xff0…

【Linux配置yum源以及基本yum指令】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言 一、yum是什么&#xff1f; 二、什么是软件包&#xff1f; 三、三种安装软件包的方式 四、yum的相关操作 4.1、搜索软件 4.2、安装软件 4.3、卸载软件 4.4、那…

Python | 七、栈 Stack、队列 Queue

栈的基础知识 是一种数据结构&#xff0c;在Python中常使用列表来模拟实现特点&#xff1a;先进后出 栈的基本操作 因为Python中通过列表模拟实现栈&#xff0c;所以以下的基本操作实际是列表的一些操作获取长度&#xff0c;使用len(stack)方法进栈&#xff0c;使用stack.app…