带你走进不一样的策略模式

欢迎来到我的博客,代码的世界里,每一行都是一个故事


在这里插入图片描述

带你走进不一样的策略模式

    • 前言
    • 策略模式简介
      • 概念解释
    • 策略模式的结构
    • 策略模式优点
    • 项目实践之bean策略
      • 构思业务
      • 策略实现
        • 策略接口实现
        • 策略上下文
        • 业务实现

前言

在编程的世界里,每一次按键都是在与代码做策略游戏。我们试图在效率、灵活性和可维护性之间找到平衡点。今天,我们要探讨的是Java中的策略模式,这个模式就像是一个老练的军师,让我们在面对不断变化的需求时能够灵活调整战略。在本文中,我们不仅要学习策略模式的理论,更要通过实战将这个强大的工具纳入我们的编程武库。准备好了吗?让我们开始这场精彩的策略之旅吧

策略模式简介

策略模式(Strategy Pattern)是一种设计模式,它使得一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。
在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。

概念解释

策略(Strategy):一个策略代表了一个算法,或者说是一个行为。在策略模式中,我们可以定义一系列算法或行为,并将每一个算法封装到具有共同接口的独立的类中。
上下文(Context):上下文是使用策略的对象。通常,它会持有一个指向策略对象的引用,并可通过该引用调用策略对象实现的算法。上下文可能会定义一个接口来让策略对象访问它的数据。
策略接口(Strategy Interface):这是一个定义每个策略或算法必须遵守的接口。它是一个共同的接口,让上下文能够在不同策略之间切换而不影响客户端。
具体策略(Concrete Strategies):实现策略接口的类,提供具体的算法或行为。

策略模式的结构

Strategy(策略接口):定义所有支持的算法的公共接口。Context 使用这个接口来调用 ConcreteStrategy 定义的算法。
ConcreteStrategy(具体策略):实现 Strategy 接口的具体类。每一个 ConcreteStrategy 提供了一个算法或行为。
Context(上下文):持有一个对 Strategy 对象的引用。它可以定义一个接口来让 Strategy 访问它的数据。

// 策略接口
public interface Strategy {
    public void execute();
}
// 具体策略A
public class ConcreteStrategyA implements Strategy {
    public void execute() {
        System.out.println("执行策略A");
    }
}
// 具体策略B
public class ConcreteStrategyB implements Strategy {
    public void execute() {
        System.out.println("执行策略B");
    }
}
// 上下文
public class Context {
    private Strategy strategy;

    // 构造方法,传入策略对象
    public Context(Strategy strategy) {
        this.strategy = strategy;
    }
    
    // 上下文接口
    public void executeStrategy() {
        strategy.execute();
    }
}
// 客户端代码
public class StrategyPatternDemo {
    public static void main(String[] args) {
        Context context = new Context(new ConcreteStrategyA()); // 使用策略A
        context.executeStrategy(); // 输出:执行策略A

        context = new Context(new ConcreteStrategyB()); // 使用策略B
        context.executeStrategy(); // 输出:执行策略B
    }
}

策略模式优点

策略模式是一种常用的设计模式,它提供了一系列显著的优点,特别是在处理算法、行为或策略需要在运行时可更换的场景中。以下是策略模式的一些主要优点:

  1. 代码复用与分离
    策略模式通过将算法封装在独立的策略类中,实现了算法的复用。这种封装也促进了算法逻辑和使用算法的客户端代码之间的分离。每个策略类负责自己的算法,使得算法的管理和维护变得更加清晰和简单。
  2. 易于扩展
    策略模式使得添加新的策略或算法变得非常容易,而不需要修改现有的代码。这是因为策略模式提供了一个共同的接口给所有的策略类,任何新的策略实现都可以通过实现这个接口加入到系统中,而不会影响到使用策略的客户端代码。这种易于扩展的特性使得系统更加灵活,能够更好地适应变化。
  3. 替换继承
    在一些情况下,使用策略模式可以避免使用继承来提供类的不同行为。在传统的面向对象设计中,继承被广泛用于扩展类的功能。然而,继承有其固有的缺点,如可能导致类层次结构变得复杂,以及子类与父类之间的紧密耦合。策略模式提供了一种替代继承的方法,通过组合的方式(即在类中引入策略对象)来改变类的行为,这样做可以提高类的灵活性和可维护性。
  4. 更好的测试性
    由于策略模式将算法的实现从其使用环境中分离出来,测试各个算法变得更加容易。每个策略类可以独立于上下文进行单元测试,这有助于识别和修复潜在的算法错误,提高代码的质量。
  5. 更好的控制算法族
    在策略模式中,所有相关的算法族都被封装在一个定义良好的策略接口后面。这不仅使得算法的管理变得容易,而且还可以在运行时动态地在不同算法之间进行切换,为客户端代码提供了更大的灵活性和控制力。
    综上所述,策略模式通过提供一种机制来分离和封装算法或行为,使得代码更加模块化、易于扩展和维护,同时也提高了代码的复用性和灵活性。这些优点使得策略模式在众多设计模式中占有一席之地。

项目实践之bean策略

构思业务

现在我有一个业务它需要根据某一个判断条件(类型)来选择调用某一bean中的相关方法,传统的实现方式如下图

202404210951557.png

对于上面的方式,会存在这样一个问题,每当我新加一个类型,就要新加一个service实现。并且我的业务中要新加判断,如果我这个业务中存在一个方法会新加一个,如果是100个可能就会新加100个。这样不仅违法了开闭原则,而且还有冗余代码且改起来费时间,最终演变为策略模式,如下图

202404211007531.png

策略实现

策略接口实现
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

/**
 * @author xiaobo
 */
public interface IDataStrategy {

    /**
     * description: 判断是否有值
     *
     * @param mainType 主要类型
     * @return boolean
     * @date 2024/4/19 15:57
     */
    boolean supports(String mainType);

}
策略上下文
package com.jxth.dasmart.bridge.configs;

import com.jxth.dasmart.bridge.modules.mid.IMidDataStrategy;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * description: 策略管理
 *
 * @author bo
 * @version 1.0
 * @date 2024/4/19 16:10
 */
@Component
@RequiredArgsConstructor
public class DataServiceManager {
    private final List<IMidDataStrategy> services;

    public IMidDataStrategy getService(String mainType) {
        return services.stream()
                .filter(service -> service.supports(mainType))
                .findFirst()
                .orElseThrow(() -> new IllegalArgumentException("No suitable service found for mainType: " + mainType));
    }
}
业务实现
public class BusinessTest {
  @Resource
  protected DataServiceManager serviceManager;

  public void test(String type){
    IDataStrategy service = serviceManager.getService(type);
    // 实现相关方法
  }
}

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

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

相关文章

【办公类-26-02】20240423 UIBOT学分自动评价(自动登录、评价和退出,全自动)

背景需求&#xff1a; 我想用UIBOT自动模拟鼠标&#xff0c;登录每位老师的账户&#xff0c;进入评价区域&#xff0c;自动选择7次“满意”&#xff0c;输入1次“无”&#xff0c;然后提交。 C Dim objExcelWorkBook,arrayRet,iRet,temp,iPID,hWeb,dictRet,XobjExcelWorkBook …

《QT实用小工具·四十一》无边框窗口

1、概述 源码放在文章末尾 该项目实现了无边框窗口效果&#xff0c;项目demo如下所示&#xff1a; 项目代码如下所示&#xff1a; #include "framelesswindow.h" #include <QGuiApplication> #include <QScreen>#ifdef Q_OS_WIN #include <window…

24深圳杯数学建模挑战赛A题6页初步思路+参考论文+保姆级答疑!!!

问题1:单个残骸的精确位置定位 建立数学模型&#xff0c;分析如果要精准确定空中单个残骸发生音爆时的位置坐标&#xff08;经度、纬度、高程&#xff09;和时间&#xff0c;至少需要布置几台监测设备&#xff1f;假设某火箭一级残骸分离后&#xff0c;在落点附近布置了7台监测…

文件上传服务器、文件展示等异步问题

问题&#xff1a; 文件上传模块&#xff1a;当文件已经上传完成&#xff0c;文件进度已经走完了&#xff0c;但是服务器响应还没有返回结果&#xff0c;出现了&#xff0c;获取不到上传后的文件路径&#xff0c;需要等待服务器返回结果后&#xff0c;才能获取文件路径并点击跳…

Linux 基本指令(上)

目录 whoami 命令 pwd 命令 ls 命令 Linux的目录结构 cd 命令 文件操作 什么是文件 touch 命令 mkdir 命令 rmdir / rm 命令 rm 删除文件&#xff1a; rm 删除目录&#xff1a; whoami 命令 whoami &#xff1a;可以看出当前登录的用户名 pwd 命令 pwd 用于显示用户当…

前端发送请求,显示超时取消

前端发送请求&#xff0c;显示超时取消 问题说明&#xff1a;后台接口请求60s尚未完成&#xff0c;前端控制台显示取消&#xff08;canceled&#xff09; 原因 1、前端设置60s超时则取消 2、后台接口响应时间过长&#xff0c;过长的原因统计的数据量多&#xff08;实际也才17…

嵌入式linux学习之arm开发板移植ssh

1.下载源码 &#xff08;1&#xff09;zlib 下载网址&#xff1a;http://www.zlib.net/fossils/ 教程中版本选择的是: zlib-1.2.11.tar.gz &#xff08;2&#xff09;openssl下载网址&#xff1a;https://www.openssl.org/source/mirror.html 教程中版本选择的是: openssl-1.1…

【Qt】.ui文件转.h文件

1、打开qt命令行 2、转换 uic -o ui.h mainwindow.ui

Linux c++ onvif客户端开发(9):GetProfiles

本文是Linux c onvif客户端开发系列文章之一&#xff1a; Linux c onvif客户端开发(1): 根据wsdl生成cpp源文件Linux c onvif客户端开发(2): 获取摄像头H264/H265 RTSP地址Linux c onvif客户端开发(3): 扫描设备Linux c onvif客户端开发(4): 扫描某个设备是否支持onvifLinux c…

js基础知识(2)

一、事件的含义 JavaScript事件是指在文档或者浏览器中发生的一些特定交互瞬间&#xff0c;比如打开某一个网页&#xff0c;浏览器加载完成后会触发load事件&#xff0c;当鼠标悬浮于某一个元素上时会触发hover事件&#xff0c;当鼠标点击某一个元素时会触发click事件等等。 三…

电子签章与SSL证书:区别与功能对比

电子签章是一种用于电子文档的签名技术&#xff0c;它通过密码学方法确保文档的完整性、真实性和签署行为的不可否认性。电子签章技术结合了图像处理技术和电子签名技术&#xff0c;使得电子文档在法律上与传统纸质文件具有同等效力。这种技术通常用于需要法律认可的电子合同、…

【Matlab函数分析】对二维或三维散点数据插值函数scatteredInterpolant

&#x1f517; 运行环境&#xff1a;Matlab &#x1f6a9; 撰写作者&#xff1a;左手の明天 &#x1f947; 精选专栏&#xff1a;《python》 &#x1f525; 推荐专栏&#xff1a;《算法研究》 #### 防伪水印——左手の明天 #### &#x1f497; 大家好&#x1f917;&#x1f91…

部署和发布

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、打包 Spring Boot 项⽬二、上传jar包至服务器三.启动项目四.停止项目总结 前言 确认服务器已安装好 Java 环境&#xff1b;确保服务器有可⽤的 MySQL&…

指标+AI:迈向智能化,让指标应用更高效

近日&#xff0c;以“DataAI&#xff0c;构建新质生产力”为主题的袋鼠云春季发布会圆满落幕&#xff0c;大会带来了一系列“AI”的数字化产品与最新行业沉淀&#xff0c;旨在将数据与AI紧密结合&#xff0c;打破传统的生产力边界&#xff0c;赋能企业实现更高质量、更高效率的…

Mac读写U盘软件哪个好用 Mac读写U盘很慢怎么解决 macbookpro读取u盘

在使用Mac电脑时&#xff0c;读写U盘是一个常见的需求&#xff0c;特别是当U盘格式为NTFS时。选择适合的软件来实现这一操作至关重要。下面我们来看Mac读写U盘软件哪个好用&#xff0c;Mac读写U盘很慢怎么解决的相关内容。 一、Mac读写U盘软件哪个好用 在Mac上选择一款适合的…

美国网站服务器解决方案

在当今互联网时代&#xff0c;网站是企业宣传、营销和销售的最好方式&#xff0c;因此&#xff0c;选择一个适合自己企业的网站服务器解决方案很重要。美国作为全球网络基础设施最发达的国家之一&#xff0c;其网站服务器解决方案具有以下特点&#xff1a; 一、安全性高 作为全…

5个方便好用的Python自动化脚本

相比大家都听过自动化生产线、自动化办公等词汇&#xff0c;在没有人工干预的情况下&#xff0c;机器可以自己完成各项任务&#xff0c;这大大提升了工作效率。 编程世界里有各种各样的自动化脚本&#xff0c;来完成不同的任务。 尤其Python非常适合编写自动化脚本&#xff0…

【JAVA】PO、VO、DAO、BO、DTO、POJO你分得清吗?

在Java开发中&#xff0c;PO、VO、DAO、BO、DTO、POJO这些词汇是比较常见的&#xff0c;每个术语都有其特定的含义和用途。下面是它们的具体区别&#xff1a; 名称简要概况用途和特定PO (Persistence Object) 持…

c++11详解

目录 1.列表初始化 2.声明 3.右值引用和移动语句 4. c11新的类功能 5. 可变参数模板 6.lambda表达式 7.包装器 8. 后言 1. 列表初始化 1.1 {}的初始化 (1) c98标准规定可以使用{}对数组以及结构体进行统一的列表初始化. struct Point {int _x;int _y; };int main() {in…

OpenStack的基本操作

1.实例类型管理 首先用管理员账号登录OpenStack 点击创建实例类型后&#xff1a;可以看见实例类型创建成功 2.项目与租户管理 Openstack有严格的项目及租户管理制度&#xff0c;在项目中使用管理员创建项目&#xff0c;然后为该项目创建一个以你姓名命名的账户为该项目的管理…