策略者模式(代码实践C++/Java/Python)————设计模式学习笔记
文章目录
- 1 设计目标
- 2 Java
- 2.1 涉及知识点
- 2.2 实现
- 2.2.1 实现两个接口飞行为和叫行为
- 2.2.2 实现Duck抽象基类(把行为接口作为类成员)
- 2.2.3 实现接口飞行为和叫行为的具体行为
- 2.2.4 具体实现鸭子
- 2.2.5 模型调用
- 3 C++(用到了大量C++2.0的知识)
- 3.1 涉及知识点
- 3.2 实现
- 3.2.1 实现飞行为和叫行为接口
- 3.2.2 实现Duck基类(使用委托/组合,把指向抽象接口类的指针作为类成员)
- 3.2.3 实现接口类的飞行为和叫行为
- 3.2.4 实现具体的鸭子行为
- 3.2.5 具体调用
- 4 Python实现
- 4.1 涉及知识点
- 4.2 实现代码
- 4.2.1 实现两个接口飞行为和叫行为
- 4.2.2 实现Duck抽象基类(把行为接口作为类成员)
- 4.2.3 实现接口飞行为和叫行为的具体行为
- 4.2.4 具体实现鸭子
- 4.2.5 模型调用
- 5 完整代码
- 6 其他知识阅读(快速入门)
1 设计目标
此篇为实现篇下,如果对策略者模式不熟,可以看知识点篇上。
实现要求:鸭子共有三种行为,游泳行为(所有鸭子都会),飞行行为(能飞/不能飞/具有火箭动力的飞行),叫声行为(嘎嘎叫/吱吱叫/什么都不会叫),不同具体鸭子(绿头鸭/模型鸭/…)飞行行为和叫声行为可能不一样。
2 Java
2.1 涉及知识点
- 接口(interface):定义一种方法约束
- 继承(extend):子类会具有父类的一般特性也会具有自身的特性,提高代码复用性。
区别:
修饰符不同:接口使用interface修饰,继承使用extends修饰。
多继承方式不同:接口支持多继承,继承只支持单继承。
定义方式不同:接口只能定义全局常量和抽象方法,继承可以定义属性、方法、变量、常量等。
作用不同:接口是一种约束,类实现接口就一定要实现它所有的方法;继承是一种扩展,继承了类,它的私有成员以外的成员变量和成员方法子类都将拥有。
- 组合(委托):把A类作为B类的成员变量,具体实现在A类中,B类对外暴露调用接口,解耦合。
- 抽象基类:不能实例化,只能作为类模版,子类需要实现起抽象方法。
- 构造函数:类的初始化方法。
2.2 实现
2.2.1 实现两个接口飞行为和叫行为
public interface FlyBehavior {public void fly();
}public interface QuackBehavior {public void quack();
}
2.2.2 实现Duck抽象基类(把行为接口作为类成员)
package com.jiangxue.strategy;public abstract class Duck {//组合(委托):策略类作为抽象基类的成员变量QuackBehavior quackBehavior;FlyBehavior flyBehavior;//定义抽象方法:子类必须要实现public abstract void display();//调用类成员的方法public void performQuack(){quackBehavior.quack();;}public void performFly(){flyBehavior.fly();}//所有子类都有的共有行为public void swim(){System.out.println("All ducks float, even decoys");}//setter方法设置鸭子行为(运行时改变行为)public void setFlyBehavior(FlyBehavior fb){flyBehavior = fb;}public void setQuackBehavior(QuackBehavior quackBehavior) {this.quackBehavior = quackBehavior;}
}
2.2.3 实现接口飞行为和叫行为的具体行为
- 具体实现飞行为接口:
public class FlyWithWings implements FlyBehavior{@Overridepublic void fly(){System.out.println("I'm flying");}
}public class FlyNoWay implements FlyBehavior{@Overridepublic void fly() {System.out.println("I can't fly");}
}public class FlyRocketPowered implements FlyBehavior{@Overridepublic void fly() {System.out.println("I'm fly with rocket!");}
}
- 具体实现叫行为接口:
public class Quack implements QuackBehavior{@Overridepublic void quack() {System.out.println("Quack");}
}public class MuteQuack implements QuackBehavior{@Overridepublic void quack() {System.out.println("<<Silence>>");}
}public class Squeak implements QuackBehavior{@Overridepublic void quack() {System.out.println("Squack");}
}
2.2.4 具体实现鸭子
- 实现绿头鸭
public class MallardDuck extends Duck{//重新构造函数public MallardDuck(){quackBehavior = new Quack();flyBehavior = new FlyWithWings();}public void display(){System.out.println("I'm a real Mallard duck");}
}
- 实现模型鸭:
public class ModelDuck extends Duck{public ModelDuck(){flyBehavior = new FlyNoWay();quackBehavior = new Quack();}@Overridepublic void display() {System.out.println("I'm a model duck");}
}
2.2.5 模型调用
public class Test {public static void main(String[] args) {//示例1Duck mallardDuck = new MallardDuck();mallardDuck.performQuack();mallardDuck.performFly();//示例2Duck model = new ModelDuck();model.performFly();//改变飞行行为model.setFlyBehavior(new FlyRocketPowered());model.performFly();; }
}
3 C++(用到了大量C++2.0的知识)
3.1 涉及知识点
- 纯虚函数(用于实现接口)【virtua和= 0】:在基类中声明的虚函数,它在基类中没有定义,但要求任何派生类都要定义自己的实现方法。有纯虚函数的类是抽象类,不能生成对象,只能派生。
- virtual析构函数:当父类指针指向子类对象时,执行释放操作,子类对象也会被释放掉。
- explicit:该构造函数只能显式调用,禁止隐式转换。
- &&(右值引用):结合了移动语义和完美转发;可以绑定到临时对象。
- 移动语义:不复制对象,而只是让新的对象名指向原对象名所指对象,并且将原对象所指的置空。
- 完美转发:可以撰写接受任意参数的函数模版,并将其转发到其他函数,目标函数会接受与其转发函数所接受的完全相同的参数。
- std::move(把实参强制转换为右值):无条件地右值类型的强制类型转换;
- std::forward:仅对绑定到右值的引用实施向右值类型的强制转换。
- 针对右值引用实施std::move,万能引用实施std::forward
- 智能指针unique_ptr:独占对象,不允许复制;动态管理分配对象的生命周期。
- make_unique函数:动态分配指定类型的内存,并返回一个指向分配内存的唯一指针。
- 子类继承父类的构造:不能直接从初始化列表初始化基类成员,应该使用父类的构造函数。
- 公有继承:基类的公有成员和保护成员的访问属性在派生类中不变
3.2 实现
3.2.1 实现飞行为和叫行为接口
class QuackBehavior{
public://纯虚函数只有函数的名字而不具备函数的功能,不能被调用,要求任何派生类都要定义自己的实现方法//有纯虚函数的类是抽象类,不能生成对象,只能派生。virtual void quack() const = 0;//virtual析构函数好处:当父类指针指向子类对象时,执行释放操作,子类对象也会被释放掉virtual ~QuackBehavior() =default;
};class FlyBehavior{
public:virtual void fly() const = 0;virtual ~FlyBehavior() = default;
};
3.2.2 实现Duck基类(使用委托/组合,把指向抽象接口类的指针作为类成员)
#include <memory>
#include "FlyBehavior.h"
#include "QuackBehavior.h"
#include <iostream>class Duck {
protected://智能指针unique_ptr:独占对象,不允许复制;动态管理分配对象的生命周期std::unique_ptr<FlyBehavior> _flyBehavior;std::unique_ptr<QuackBehavior> _quackBehavior;
public://explicit表示该构造函数只能显式调用,禁止隐式转换。/** 移动语义:不复制对象,而只是让新的对象名指向原对象名所指对象,并且将原对象所指的置空。* 完美转发:可以撰写接受任意参数的函数模版,并将其转发到其他函数,目标函数会接受与其转发函数所接受的完全相同的参数。* &&(右值引用):结合了移动语义和完美转发;可以绑定到临时对象。* std::move(把实参强制转换为右值):无条件地右值类型的强制类型转换;* std::forward:仅对绑定到右值的引用实施向右值类型的强制转换。* 针对右值引用实施std::move,万能引用实施std::forward*/explicit Duck(std::unique_ptr<FlyBehavior> &&flyBehavior ={},std::unique_ptr<QuackBehavior> &&quackBehavior={}):_flyBehavior(std::move(flyBehavior)),_quackBehavior(std::move(quackBehavior)){}//上下文允许在运行时替换策略对象。void setFlyBehavior(std::unique_ptr<FlyBehavior>&&flyBehavior){_flyBehavior = std::move(flyBehavior);}void setQuackBehavior(std::unique_ptr<QuackBehavior>&&quackBehavior){_quackBehavior = std::move(quackBehavior);}//执行飞void performFly() const{_flyBehavior->fly();}//执行叫void performQuack() const{_quackBehavior->quack();}void swim() const{std::cout<<"All ducks float, even decoys"<<std::endl;}virtual void display() const = 0;};
3.2.3 实现接口类的飞行为和叫行为
- 实现飞行为:
#include <iostream>
#include "FlyBehavior.h"//公有继承:基类的公有成员和保护成员的访问属性在派生类中不变
class FlyWithWings: public FlyBehavior{
public:void fly() const override{std::cout<<"I'm flying"<<std::endl;}
};class FlyNoWay: public FlyBehavior{
public:void fly() const override{std::cout<<"I can't fly"<<std::endl;}
};class FlyRocketPowered : public FlyBehavior{
public:void fly() const override{std::cout<<"I'm fly with rocket!"<<std::endl;}
};
- 实现叫行为:
#include "QuackBehavior.h"
#include <iostream>class Quack: public QuackBehavior{void quack() const override{std::cout<<"quack"<<std::endl;}
};class MuteQuack : public QuackBehavior{
public:void quack() const override{std::cout<<"<<Silence>>"<<std::endl;}
};class Squeak: public QuackBehavior{void quack() const override{std::cout<<"Squack"<<std::endl;}
};
3.2.4 实现具体的鸭子行为
- 绿头鸭
#include "Duck.h"
#include "Quack.h"
#include "FlyWithWings.h"
#include <iostream>class MallardDuck : public Duck{
public://子类继承父类的构造//不能直接从初始化列表初始化基类成员,应该使用父类的构造函数explicit MallardDuck(std::unique_ptr<FlyWithWings>&& flyWithWings ={},std::unique_ptr<Quack>&& quack={}): Duck(std::move(flyWithWings), std::move(quack)){}//虚函数方法重写void display() const override{std::cout<<"I'm a real Mallard duck"<<std::endl;}};
- 模型鸭
#include "Duck.h"
#include "FlyNoWay.h"
#include "Quack.h"class ModelDuck :public Duck{
public:explicit ModelDuck(std::unique_ptr<FlyNoWay>&& flyNoWay,std::unique_ptr<Quack>&& quack): Duck(std::move(flyNoWay), std::move(quack)){}void display() const override{std::cout<<"I'm a model duck"<<std::endl;}};
3.2.5 具体调用
#include "MallardDuck.h"
#include "ModelDuck.h"
#include "FlyRocketPowered.h"void testCode() {//make_unique函数:动态分配指定类型的内存,并返回一个指向分配内存的唯一指针MallardDuck mallardDuck(std::make_unique<FlyWithWings>(),std::make_unique<Quack>());mallardDuck.performQuack();mallardDuck.performFly();ModelDuck modelDuck(std::make_unique<FlyNoWay>(),std::make_unique<Quack>());modelDuck.performFly();modelDuck.setFlyBehavior(std::make_unique<FlyRocketPowered>());modelDuck.performFly();}int main() {testCode();return 0;
}
4 Python实现
4.1 涉及知识点
- 抽象基类(继承ABC):不能被实例化,只能被继承。
- 抽象方法(
@abstractmethod
):继承的子类必须实现的方法。 - 属性(
@property,@flyBehavior.setter
):调用时不需要加(),为的是提供更加友好访问类数据的方式。 - 构造函数(
def __init__
):初始化类成员变量。 - 继承(
super().__init__
):继承父类的属性。 from __future__ import annotations
:允许你在程序中声明变量或函数的类型,并由编译器或其他工具来检查代码的类型是否正确。有助于提高代码的可读性,并且有助于发现类型错误。
4.2 实现代码
4.2.1 实现两个接口飞行为和叫行为
from abc import ABC, abstractmethod# 抽象基类
class FlyBehavior(ABC):# 抽象方法@abstractmethoddef fly(self):passclass QuackBehavior(ABC):@abstractmethoddef quack(self):pass
4.2.2 实现Duck抽象基类(把行为接口作为类成员)
class Duck(ABC):def __init__(self, flyBehavior: FlyBehavior, quackBehavior: QuackBehavior) -> None:self._flyBehavior = flyBehaviorself._quackBehavior = quackBehavior@abstractmethoddef perform(self) -> None:passdef performFly(self) -> None:return self._flyBehavior.fly()def performQuack(self) -> None:return self._quackBehavior.quack()@propertydef flyBehavior(self) -> FlyBehavior:return self._flyBehavior@propertydef quackBehavior(self) -> QuackBehavior:return self._quackBehavior@flyBehavior.setterdef flyBehavior(self, fly: FlyBehavior) -> None:self._flyBehavior = fly@quackBehavior.setterdef quackBehavior(self, quack: QuackBehavior) -> None:self._quackBehavior = quackdef swim(self) -> None:print("All ducks float, even decoys")
4.2.3 实现接口飞行为和叫行为的具体行为
- 具体实现飞行为接口:
class FlyWithWings(FlyBehavior):def fly(self) -> None:print("I'm flying")class FlyNoWay(FlyBehavior):def fly(self) -> None:print("I can't fly")class FlyRocketPowered(FlyBehavior):def fly(self) -> None:print("I'm fly with rocket!")
- 具体实现叫行为接口:
class Quack(QuackBehavior):def quack(self) -> None:print("Quack")class Square(QuackBehavior):def quack(self) -> None:print("Squack")class MuteQuack(QuackBehavior):def quack(self) -> None:print("<<Silence>>")
4.2.4 具体实现鸭子
- 实现绿头鸭
class ModelDuck(Duck):def __init__(self, flyBehavior: FlyNoWay, quackBehavior: Quack) -> None:super().__init__(flyBehavior, quackBehavior)# 下面的初始化方法,并不能继承父类的属性# _flyBehavior = flyBehavior# _quackBehavior = quackBehaviordef perform(self) -> None:print("I'm a model duck")
- 实现模型鸭:
class MallardDuck(Duck):def __int__(self, flyBehavior: FlyWithWings, quackBehavior: Quack) -> None:super().__init__(flyBehavior, quackBehavior)def perform(self) -> None:print("I'm a real Mallard duck")
4.2.5 模型调用
# import sys , os
# base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# sys.path.append(base_dir)
# 没有把当前项目加入到PYTHONPATH环境变量from Strategy.duck import *if __name__ == "__main__":mallardDuck = MallardDuck(FlyWithWings(), Quack())mallardDuck.performQuack()mallardDuck.performFly()modelDuck = ModelDuck(FlyNoWay(), Quack())modelDuck.performFly()modelDuck.flyBehavior = FlyRocketPowered()modelDuck.performFly()
5 完整代码
完整的实现代码,见Gitee仓库。如果对您有用的话,欢迎留下star,谢谢。
6 其他知识阅读(快速入门)
Java快速入门
Python快速入门
深入了解C++2.0
相关文章:

策略者模式(代码实践C++/Java/Python)————设计模式学习笔记
文章目录 1 设计目标2 Java2.1 涉及知识点2.2 实现2.2.1 实现两个接口飞行为和叫行为2.2.2 实现Duck抽象基类(把行为接口作为类成员)2.2.3 实现接口飞行为和叫行为的具体行为2.2.4 具体实现鸭子2.2.5 模型调用 3 C(用到了大量C2.0的知识&…...
vue2/Vue3项目中,通过请求接口来刷新列表中的某个字段(如:Axios)
vue2/Vue3项目中,通过请求接口来刷新列表中的某个字段。可以使用 Vue 的异步请求库(如 Axios)来发送请求,并在请求成功后更新相应的字段。 示例如下(Vue2): 简单的示例如下,假设列…...
Java多线程锁定
前言 利用多线程编程虽然能极大地提升运行效率,但是多线程本身的不稳定也会带来一系列的问题,其中最经典莫过于售票问题;这时就需要人为地加以限制和干涉已解决问题,譬如今日之主题——锁定。 锁定是我们在多线程中用来解决售票…...

【C 数据结构】单链表
文章目录 【 1. 基本原理 】1.1 链表的节点1.2 头指针、头节点、首元节点 【 2. 链表的创建 】2.0 创建1个空链表(仅有头节点)2.1 创建单链表(头插入法)*2.2 创建单链表(尾插入法) 【 3. 链表插入元素 】【…...

[MAUI]集成富文本编辑器Editor.js至.NET MAUI Blazor项目
文章目录 获取资源从源码构建从CDN获取获取扩展插件 创建项目创建控件创建Blazor组件初始化保存销毁编写渲染逻辑 实现只读/编辑功能切换模式获取只读模式状态响应切换事件 实现明/暗主题切换项目地址 Editor.js 是一个基于 Web 的所见即所得富文本编辑器,它由CodeX…...

Spring Boot | Spring Boot 整合 “Servlet三大组件“ ( Servlet / Filter / Listene )
目录: Spring Boot 整合 "Servlet三大组件" :1. 使用 "组件注册" 的方式 "整合Servlet三大组件" ( 实际操作为 : 创建自定义的"三大组件"对象 结合刚创建"的自定义组件对象"来 将 XxxRegistrationBean对象 通过…...

错误分析 (Machine Learning研习十九)
错误分析 您将探索数据准备选项,尝试多个模型,筛选出最佳模型,使用 Grid SearchCV微调其超参数,并尽可能实现自动化。在此,我们假设您已经找到了一个有前途的模型,并希望找到改进它的方法。其中一种方法就…...

SQL系统函数知识点梳理(Oracle)
这里写目录标题 函数系统函数转换函数to_date()to_char()将数值转换成字符格式 添加货币符号将日期转换成字符 其他不常用的转换函数 字符型函数连接函数大小写转换函数大写转换小写转换首字母大写,其余的小写 替换函数去除空格函数截取函数填充函数获取字符长度函数…...

面试突击---MySQL索引
面试突击---MYSQL索引 面试表达技巧:1、谈一下你对于mysql索引的理解?(为什么mysql要选择B树来存储索引)2、索引有哪些分类?3、聚簇索引与非聚簇索引4、回表、索引覆盖、最左匹配原则、索引下推(1ÿ…...
关注 | 我国已对百种产品实施强制性产品认证
市场监管总局在7日举行的新闻发布会上介绍,该局日前发布《市场监管总局关于对商用燃气燃烧器具等产品实施强制性产品认证管理的公告》,对具有较高安全风险的商用燃气燃烧器具、阻燃电线电缆、电子坐便器、电动自行车乘员头盔、可燃气体探测报警产品、水性…...

虚幻引擎架构自动化及蓝图编辑器高级开发进修班
课程名称:虚幻引擎架构自动化及蓝图编辑器高级开发进修班 课程介绍 大家好 我们即将推出一套课程 自动化系统开发。 自动化技术在项目开发的前中后期都大量运用。如何您是一家游戏公司,做的是网络游戏,是不是经常会遇到程序员打包加部署需…...

Weakly Supervised Audio-Visual Violence Detection 论文阅读
Weakly Supervised Audio-Visual Violence Detection 论文阅读 摘要III. METHODOLOGYA. Multimodal FusionB. Relation Modeling ModuleC. Training and Inference IV. EXPERIMENTSV. CONCLUSION阅读总结 文章信息: 发表于:IEEE TRANSACTIONS ON MULTIME…...
华为海思数字芯片设计笔试第六套
声明 下面的题目作答都是自己认为正确的答案,并非官方答案,如果有不同的意见,可以评论区交流。 这些题目也是笔者从各个地方收集的,感觉有些题目答案并不正确,所以在个别题目会给出自己的见解,欢迎大家讨论…...

重绘和重排:概念、区别和应用示例
还是大剑师兰特:曾是美国某知名大学计算机专业研究生,现为航空航海领域高级前端工程师;CSDN知名博主,GIS领域优质创作者,深耕openlayers、leaflet、mapbox、cesium,canvas,webgl,ech…...

创建k8s deploy yaml文件的imagePullSecrets语句
镜像仓库是harbor kubectl create secret docker-registry key --docker-server192.168.0.190 --docker-usernameadmin --docker-passwordHarbor12345...

大模型预测结果导入到Doccano,人工修正预测不准的数据
背景 使用大语言模型做实体识别的实验时,发现大模型关于实体的边界预测一直不准。 主要原因在于当时找了很多同学标注数据,由于不同组同学关于实体的边界没有统一,故导致数据集中实体边界也没统一。 (找太多人标,会有…...
python三方库_ciscoconfparse学习笔记
文章目录 介绍使用基本原理父子关系 属性ioscfg 获取配置信息,返回列表is_config_line 判断是否是配置行is_intf 判断IOSCfgLine是不是interfaceis_subintf 判断IOSCfgLine是不是子接口lineage 不知道用法is_ethernet_intf 判断IOSCfgLine是否是以太网接口is_loopback_intf 判断…...

HDFS详解(Hadoop)
Hadoop 分布式文件系统(Hadoop Distributed File System,HDFS)是 Apache Hadoop 生态系统的核心组件之一,它是设计用于存储大规模数据集并运行在廉价硬件上的分布式文件系统。 1. 分布式存储: HDFS 将文件分割成若干块…...

python创建word文档并向word中写数据
一、docx库的安装方法 python创建word文档需要用到docx库,安装命令如下: pip install python-docx 注意,安装的是python-docx。 二、使用方法 使用方法有很多,这里只介绍创建文档并向文档中写入数据。 import docxmydocdocx.Do…...

MongoDB的安装配置及使用
文章目录 前言一、MongoDB的下载、安装、配置二、检验MongoDB是否安装成功三、Navicat 操作MongoDB四、创建一个集合,存放三个文档总结 前言 本文内容: 💫 MongoDB的下载、安装、配置 💫 检验MongoDB是否安装成功 ❤️ Navicat 操…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...
【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论
路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中(图1): mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...
Redis:现代应用开发的高效内存数据存储利器
一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发,其初衷是为了满足他自己的一个项目需求,即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源,Redis凭借其简单易用、…...
LRU 缓存机制详解与实现(Java版) + 力扣解决
📌 LRU 缓存机制详解与实现(Java版) 一、📖 问题背景 在日常开发中,我们经常会使用 缓存(Cache) 来提升性能。但由于内存有限,缓存不可能无限增长,于是需要策略决定&am…...

从“安全密码”到测试体系:Gitee Test 赋能关键领域软件质量保障
关键领域软件测试的"安全密码":Gitee Test如何破解行业痛点 在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的"神经中枢"。从国防军工到能源电力,从金融交易到交通管控,这些关乎国计民生的关键领域…...

关于easyexcel动态下拉选问题处理
前些日子突然碰到一个问题,说是客户的导入文件模版想支持部分导入内容的下拉选,于是我就找了easyexcel官网寻找解决方案,并没有找到合适的方案,没办法只能自己动手并分享出来,针对Java生成Excel下拉菜单时因选项过多导…...
Modbus RTU与Modbus TCP详解指南
目录 1. Modbus协议基础 1.1 什么是Modbus? 1.2 Modbus协议历史 1.3 Modbus协议族 1.4 Modbus通信模型 🎭 主从架构 🔄 请求响应模式 2. Modbus RTU详解 2.1 RTU是什么? 2.2 RTU物理层 🔌 连接方式 ⚡ 通信参数 2.3 RTU数据帧格式 📦 帧结构详解 🔍…...

数据结构:递归的种类(Types of Recursion)
目录 尾递归(Tail Recursion) 什么是 Loop(循环)? 复杂度分析 头递归(Head Recursion) 树形递归(Tree Recursion) 线性递归(Linear Recursion)…...