设计模式: 策略模式

news2024/11/18 8:50:10

文章目录

  • 一、什么是策略模式
  • 二、策略模式结构
  • 三、使用场景+案例分析
    • 1、使用场景
    • 2、案例分析
      • (1)消除条件分支

一、什么是策略模式

策略模式是一种行为型设计模式,它允许定义一组算法,并将每个算法封装在独立的类中,使它们可以互相替换。策略模式通过将算法的使用与算法的实现分离,使得算法可以独立于客户端而变化。

  • 在策略模式中,通常会有一个上下文(Context)类,该类包含一个策略接口(Strategy),以及具体的策略类(Concrete Strategies)。上下文类将具体的任务委托给策略接口,在运行时可以根据需要切换不同的策略类,从而达到动态改变算法行为的目的。
  • 策略模式的核心思想是面向接口编程,而不是面向实现编程。这种设计模式提供了一种灵活的方式来管理和复用算法,同时使得算法的扩展变得更加容易。它适用于需要根据不同情况选择不同算法的场景,例如排序、搜索、计算等问题。

总结起来,策略模式通过将算法封装成独立的类,使得可以在运行时动态地选择和切换算法,从而提高代码的可维护性、扩展性和复用性。

二、策略模式结构

在这里插入图片描述

三、使用场景+案例分析

1、使用场景

策略模式通常适用于以下场景:

  • 多算法选择:当需要在运行时根据情况选择不同的算法时,可以使用策略模式。例如,对于排序算法,根据数据量的不同可能选择快速排序、冒泡排序或插入排序等。

  • 消除条件分支:当代码中存在大量的条件分支语句,并且这些条件分支都是根据相同的输入来选择不同的行为时,可以考虑使用策略模式来消除这些条件分支。

  • 算法的封装和复用:当系统中存在多个类似的算法,但它们的实现细节不同,可以将这些算法封装成独立的策略类,以便复用和维护。

  • 可扩展性:当需要为系统提供一种灵活、可拓展的方式来添加新的算法或行为时,策略模式可以帮助实现这一点,而无需修改现有的代码。

  • 单一职责原则:当需要遵循单一职责原则,即每个类应该只负责一种功能时,策略模式可以将不同的算法分离到单独的策略类中,使得每个类都专注于一种算法。

总的来说,策略模式适用于需要动态地切换算法、消除条件分支、提高可维护性和可扩展性的场景。通过策略模式,可以更好地管理和组织算法,使系统更加灵活和易于维护。

2、案例分析

(1)消除条件分支

在元数据管理系统中有可视化建表的功能,在向底层建表的过程中不同类型的数据源有不同的分区形式,原有代码的处理形式是使用if语句判断数据源类型使用对应的方式对分区进行处理。每次新接进来的数据源如果有分区的特性需要需要if语句进行处理,这样的处理方式并不符合开闭原则(对扩展开放,对修改关闭)。现在我们基于BeanPostProcessor+注解+注册管理器形式的策略模式来取消条件分支。

  • 策略(strategy)
public interface IConvertPartition {
    void processPartition(ProcessParam param);
    void partitionParams(PartitionParam param);
}
  • 具体策略(concrete strategy)
    不同的数据源有不同的实现形式,仅仅举例一个数据源的具体策略:
@ConvertPartition(tableType = TableType.KINGBASE_ES, dataType = DataType.KINGBASE_ES)
@Slf4j
public class KingbaseConverPartition implements IConvertPartition {
    @Override
    public void processPartition(ProcessParam param) {
        //具体的分区处理逻辑
    }
    @Override
    public void partitionParams(PartitionParam param){
    //具体的分区处理逻辑
    }
}    
  • 上下文(context)
import com.alibaba.excel.util.CollectionUtils;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
@Slf4j
public class ConvertDraftPartitionUtilsContext {
    /**
     * partition转换 处理器
     */
    private static final Map<TableType, IConvertPartition>  CONVERT_DRAFT_UTILS_MAP = new HashMap<>();
    private static final Map<DataType, IConvertPartition> TABLE_PUBLISH_DATATYPE_MAP = new HashMap<>();

    public static <T> void register(T dataType, IConvertPartition convertPartition) {
        if (dataType instanceof TableType) {
            CONVERT_DRAFT_UTILS_MAP.putIfAbsent((TableType)dataType, convertDraftPartition);
        } else if (dataType instanceof DataType) {
            TABLE_PUBLISH_DATATYPE_MAP.put((DataType) dataType, convertDraftPartition);
        }

    }

    public static IConvertPartition getIConvertPartition(TableType  dataType) {
        return CONVERT_DRAFT_UTILS_MAP.get(dataType);
    }
    public static Set<TableType> getTableTypes() {
        Set<TableType> tableTypes = CONVERT_DRAFT_UTILS_MAP.keySet();
        log.info("convert draft partition table type list: {}", tableTypes);
        if (CollectionUtils.isEmpty(tableTypes)) {
            return Collections.emptySet();
        }
        return tableTypes;
    }

    public static void processPartition(TableType  dataType, ProcessParam param) {
        IConvertPartition iConvertPartition = getIConvertPartition(dataType);
        if (!Objects.isNull(iConvertPartition)) {
            log.info("{} start process partition", dataType.getCode());
            iConvertPartition.processPartition(param);
        }
    }

    public static void processParam(DataType  dataType, PartitionParam param) {
        IConvertPartition iConvertPartition = TABLE_PUBLISH_DATATYPE_MAP.get(dataType);
        if (!Objects.isNull(iConvertPartition)) {
            log.info("{} start process partition params", dataType.getDataTypeName());
            iConvertPartition.partitionParams(param);
        }
    }

    public static Set<TableType> getTableTypeWithPartitions() {
        log.info("The type of a table with partitions: {}", CONVERT_DRAFT_UTILS_MAP.keySet());
        return CONVERT_DRAFT_UTILS_MAP.keySet();
    }

}

  • 注解
@Component
@Inherited
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ConvertPartition {
    DataType dataType();
    TableType tableType();
}
  • BeanPostProcessor
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

import java.util.Objects;
@Component
@Slf4j
public class ConvertPartitionRegisterProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof IConvertPartition) {
            Class<?> aClass = bean.getClass();
            log.info("the convertDraftPartition of [ {} ] begin to register", aClass.getSimpleName());
            ConvertPartition annotation = aClass.getAnnotation(ConvertPartition.class);
            if (Objects.isNull(annotation)) {
                return bean;
            }
            DataType dataType = annotation.dataType();
            TableType tableType = annotation.tableType();
            registerHandler(aClass, bean, dataType, tableType);
        }
        return bean;
    }

    private void registerHandler(Class<?> aClass, Object bean, Object... dataTypes){
        if (ArrayUtils.isNotEmpty(dataTypes)) {
            for (Object dataType : dataTypes) {
                if (!Objects.isNull(dataType)) {
                    ConvertPartitionUtilsContext.register(dataType, (IConvertPartition)bean);
                    log.info("the [ {} ] register success", aClass.getSimpleName());
                }
            }
        }
    }
}

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

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

相关文章

UE5 C++ 创建可缩放的相机

一.要将相机设置在Pawn类里 1.在MyPawn头文件里&#xff0c;加上摇臂和相机组件 #include "GameFramework/SpringArmComponent.h" #include "Camera/CameraComponent.h" 2.在Pawm里声明SceneComponet&#xff0c;SpringArmComponent,CameraComponent组件…

新手入门C语言之其他操作符以及操作符属性

一.逗号操作符 1.形式&#xff1a; exp1, exp2, exp3 ......逗号表达式&#xff1a;由逗号隔开的一串表达式 2.执行过程&#xff1a;从左到右依次执行每一个表达式&#xff0c;表达式的结果是最后一个表达式的结果 int main() {int a 1;int b 2;int c (a > b, a b…

给定长度为n(n<=20)的数组a,-20<=ai<=20, 每次操作选择i,j,使a[i] += a[j], 在31次操作内使a不递减,输出每次操作的i,j

题目 思路&#xff1a; #include <bits/stdc.h> using namespace std; #define int long long #define pb push_back #define fi first #define se second #define lson p << 1 #define rson p << 1 | 1 const int maxn 1e6 5, inf 1e18, maxm 4e4 5, …

SpringBoot项目实现文件上传,MINIO+OSS阿里云

MINIO 安装以及部署 官网&#xff1a;MinIO | Code and downloads to create high performance object storage 下载后是一个minio.exe的文件&#xff0c;可以先创一个文件夹来存放数据以及文件 在文件的目录下cmd进入控制台 minio.exe server data 启动成功后控制台会打印账…

代码随想录算法训练营第59天 | 583.两个字符串的删除操作 + 72.编辑距离 + 编辑距离总结篇

今日任务 583. 两个字符串的删除操作 72. 编辑距离 编辑距离总结篇 583.两个字符串的删除操作 - Medium 题目链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 给定两个单词 word1 和 word2 &#xff0c;返回使得 word1 和 word2 相同所需的最小步数。 每步 可以…

IntelliJ IDEA 创建Spring Boot 项目整合jdbc详细步骤

IntelliJ IDEA 创建Spring Boot 项目&整合jdbc详细步骤 1、打开 IntelliJ IDEA 软件2、使用 "Spring Initializr" 作为项目类型&#xff0c;新建项目工程3、选择对应的SpringBoot版本和依赖4、Spring Boot 项目的结构5、创建一个TestController&#xff0c;并运行…

个性化纹身设计,Midjourney带你探索独一无二的艺术之美

hello,大家好&#xff0c;欢迎回来。 在当今社会&#xff0c;纹身已经变得非常常见。 在寻求与众不同的个性化纹身时&#xff0c;你是否曾经为了找不到独特的设计而苦恼&#xff1f; 现在&#xff0c;Midjourney将为你打开一扇全新的艺术之门&#xff0c;引领你探索纹身设计…

matplotlib绘图初步

文章目录 绘制曲线图完整流程图像属性 绘制曲线图 matplotlib是python中最常用的可视化库&#xff0c;提供了不同坐标系下的二十余种常用图像&#xff0c;并且提供了动态图像绘制的方法&#xff0c;可以满足科学计算中的绝大多数可视化需求。而在matplotlib中&#xff0c;绝大…

基于Redis限流(固定窗口、滑动窗口、漏桶、令牌桶)(肝货!!!)

近期redis复习的比较多&#xff0c;在限流这方面发现好像之前理解的限流算法有问题&#xff0c;索性花了一天“带薪摸鱼”时间肝了一天&#xff0c;有问题可以评论区探讨。 废话不多说&#xff0c;正片开始 目录 Maven固定窗口滑动窗口算法漏桶算法令牌桶算法 Maven 有些不用的…

[HTML]Web前端开发技术28(HTML5、CSS3、JavaScript )JavaScript基础——喵喵画网页

希望你开心&#xff0c;希望你健康&#xff0c;希望你幸福&#xff0c;希望你点赞&#xff01; 最后的最后&#xff0c;关注喵&#xff0c;关注喵&#xff0c;关注喵&#xff0c;佬佬会看到更多有趣的博客哦&#xff01;&#xff01;&#xff01; 喵喵喵&#xff0c;你对我真的…

【计网】TCP的三次握手四次挥手

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;JAVA ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 三次握手&#xff08;Connection Establishment&#xff09; 四次挥手&#xff08;Connection Termination&#xff09; 结语 我…

Echarts与后台(mongoose)交互

Echarts引入地址可参考 echarts组件引入 <template><div><div id"main" style"width: 600px;height:400px;"></div></div> </template><script setup> import { onMounted, ref } from vue; import * as echa…

JavaScript 数组、遍历

数组 多维数组&#xff1a;数组里面嵌套 一层数组为二维数组。一维数组的使用频率是最高的。 如果数组访问越界会返回undefined。 数组遍历 数组方法Array.isArray() 这个方法可以去判定一个内容是否是数组。

32单片机基础:GPIO输出

目录 简介&#xff1a; GPIO输出的八种模式 STM32的GPIO工作方式 GPIO支持4种输入模式&#xff1a; GPIO支持4种输出模式&#xff1a; 浮空输入模式 上拉输入模式 下拉输入模式 模拟输入模式&#xff1a; 开漏输出模式&#xff1a;&#xff08;PMOS无效&#xff0c;就…

基于SpringBoot的气象数据监测分析大屏

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下&#xff0c;你想解决的问…

简单聊聊如何零基础入门机器视觉

在这个充满科技奇迹的时代里&#xff0c;机器视觉像一面魔法镜&#xff0c;赋予机器以“视觉”&#xff0c;让它们能够理解和解释这个世界。对于热爱探索新知的大学生和研究生们来说&#xff0c;学习机器视觉不仅是开启未来科技大门的钥匙&#xff0c;更是一次激动人心的冒险之…

RisingWave最佳实践-利用Dynamic filters 和 Temporal filters 实现监控告警

心得的体会 刚过了年刚开工&#xff0c;闲暇之余调研了分布式SQL流处理数据库–RisingWave&#xff0c;本人是Flink&#xff08;包括FlinkSQL和Flink DataStream API&#xff09;的资深用户&#xff0c;但接触到RisingWave令我眼前一亮&#xff0c;并且拿我们生产上的监控告警…

备战蓝桥杯————双指针技巧巧解数组1

利用双指针技巧来解决七道与数组相关的题目。 两数之和 II - 输入有序数组&#xff1a; 给定一个按升序排列的数组&#xff0c;找到两个数使它们的和等于目标值。可以使用双指针技巧&#xff0c;在数组两端设置左右指针&#xff0c;根据两数之和与目标值的大小关系移动指针。 …

动态规划--持续更新篇

将数字变成0的操作次数 1.题目 2.思路 在numberOfSteps函数中&#xff0c;首先设置f[0]为0&#xff0c;因为0已经是0了&#xff0c;不需要任何步骤。然后&#xff0c;使用一个for循环从1迭代到输入的整数num。对于每个整数i&#xff0c;如果i是奇数&#xff0c;则将f[i]设置为…

uniapp离线打包(使用Android studio打包)

一、准备工作 安装HbuilderX&#xff0c;记住版本号下载对应HbuilderX版本的Android离线SDK&#xff0c;如我使用3.6.18版本打包&#xff0c;则对应应下载3.6.18版本的SDK&#xff08;官网不提供旧版本的SDK&#xff0c;有些需要自己找&#xff09;官网下载地址&#xff1a;ht…