当前位置: 首页 > news >正文

设计模式: 策略模式

文章目录

  • 一、什么是策略模式
  • 二、策略模式结构
  • 三、使用场景+案例分析
    • 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 {@Overridepublic void processPartition(ProcessParam param) {//具体的分区处理逻辑}@Overridepublic 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 {@Overridepublic 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());}}}}
}

相关文章:

  • 猫毛过敏却想养猫时?如何缓解猫毛过敏?宠物空气净化器推荐
  • Linux——缓冲区封装系统文件操作
  • 3.WEB渗透测试-前置基础知识-快速搭建渗透环境(上)
  • 手写commonJS里面的require函数
  • 基于相位的运动放大:如何检测和放大难以察觉的运动(01/2)
  • 【Java EE初阶二十一】http的简单理解(二)
  • 数据结构 计算结构体大小
  • Spring Boot 手写starter!!!
  • 第二章、FFmpeg增加RTP协议外部扩展信息解析
  • 蓝桥杯嵌入式第12届真题(完成) STM32G431
  • 内核内存回收关键隐藏变量之page引用计数
  • unity学习(38)——创建(create)角色脚本(panel)--EventSystem
  • 前端不传被删记录的id怎么删除记录,或子表如何删除记录
  • 【深度学习目标检测】十九、基于深度学习的芒果计数分割系统-含数据集、GUI和源码(python,yolov8)
  • 【C语言】详解计算机二级c语言程序题
  • miniui datagrid 的客户端分页解决方案 - CS结合
  • OpenStack安装流程(juno版)- 添加网络服务(neutron)- controller节点
  • PHP 使用 Swoole - TaskWorker 实现异步操作 Mysql
  • RedisSerializer之JdkSerializationRedisSerializer分析
  • SpringBoot几种定时任务的实现方式
  • text-decoration与color属性
  • Vue2 SSR 的优化之旅
  • Work@Alibaba 阿里巴巴的企业应用构建之路
  • 阿里云前端周刊 - 第 26 期
  • 聊聊sentinel的DegradeSlot
  • 前端_面试
  • 使用Envoy 作Sidecar Proxy的微服务模式-4.Prometheus的指标收集
  • 体验javascript之美-第五课 匿名函数自执行和闭包是一回事儿吗?
  • 一个SAP顾问在美国的这些年
  • 找一份好的前端工作,起点很重要
  • Spring第一个helloWorld
  • 如何用纯 CSS 创作一个货车 loader
  • ​软考-高级-信息系统项目管理师教程 第四版【第14章-项目沟通管理-思维导图】​
  • #FPGA(基础知识)
  • #Linux(Source Insight安装及工程建立)
  • (done) 两个矩阵 “相似” 是什么意思?
  • (附源码)springboot金融新闻信息服务系统 毕业设计651450
  • (附源码)ssm跨平台教学系统 毕业设计 280843
  • (附源码)计算机毕业设计SSM智慧停车系统
  • (考研湖科大教书匠计算机网络)第一章概述-第五节1:计算机网络体系结构之分层思想和举例
  • **登录+JWT+异常处理+拦截器+ThreadLocal-开发思想与代码实现**
  • *p++,*(p++),*++p,(*p)++区别?
  • ... 是什么 ?... 有什么用处?
  • .NET 使用 JustAssembly 比较两个不同版本程序集的 API 变化
  • .Net8 Blazor 尝鲜
  • /dev/VolGroup00/LogVol00:unexpected inconsistency;run fsck manually
  • @JoinTable会自动删除关联表的数据
  • @WebService和@WebMethod注解的用法
  • []新浪博客如何插入代码(其他博客应该也可以)
  • [acm算法学习] 后缀数组SA
  • [Android]使用Retrofit进行网络请求
  • [Angular] 笔记 9:list/detail 页面以及@Output
  • [Angularjs]ng-select和ng-options
  • [ARC066F]Contest with Drinks Hard
  • [ArcPy百科]第三节: Geometry信息中的空间参考解析