探索设计模式的魅力:掌握命令模式-解锁软件设计的‘遥控器’
🌈 个人主页:danci_
🔥 系列专栏:《设计模式》
💪🏻 制定明确可量化的目标,并且坚持默默的做事。
引言:探索命令模式的奥秘
软件设计领域充满挑战与机遇,命令模式作为关键要素,以优雅方式组织应用程序中的行为和请求。命令模式在现实世界中无处不在,如遥控器按钮或语音助手指令,封装请求或操作为对象,便于灵活处理不同请求、队列、日志及可撤销操作。从简单GUI到复杂企业级事务管理,命令模式均发挥重要作用。
命令模式的魅力在于其提供的松耦合设计方式。它将发起请求的对象(Invoker)与实现请求的对象(Receiver)之间的依赖解耦,引入了具体命令(ConcreteCommand)类来作为二者之间的沟通桥梁。这不仅增强了系统的灵活性,使得命令的添加和扩展变得更为平易,同时也方便了事务逻辑和历史记录的实现,比如撤销/重做功能,这在诸如文本编辑器等需要这类功能的应用程序中至关重要。
本文将深入解析命令模式的精粹,从基本概念入手,阐述其在软件设计中的实际应用,探讨如何高效地实现命令模式,并揭示其背后的设计哲学。我们会通过实例验证命令模式的多功能性,并指出在实现过程中需要注意的常见陷阱和挑战。
文章的结构安排如下:
- 传统的实现方式
- 模式讲解
- 回顾与展望
随着我们走进命令模式的奥秘世界,将揭示如何巧妙地利用它来构建模块化、灵活和可维护性高的软件系统。
文章目录
- 一、传统实现方式
- 场景案例
- 一坨坨代码实现
- 有何问题
- 二、命令模式讲解
- 结构图及说明
- 示例代码
- 使用命令模式重构案例
- 克服的问题
- 三、回顾与展望
- 优点
- 缺点
- 应用场景
- 未来展望
一、传统实现方式
场景案例
一个经典的案例场景是“远程遥控器”(Remote Control)的设计。在这个场景中,我们可以将遥控器上的每个按钮看作是一个命令对象,而遥控器本身则是一个命令的调用者。当用户按下遥控器上的某个按钮时,遥控器就会调用相应的命令对象来执行操作。 |
一坨坨代码实现
一个简单的、直接的实现方法可能是直接在遥控器类中为每一个可能的动作定义一个方法。当一个按钮被按下时,就直接调用对应的方法。这种做法会使得遥控器类和实际执行动作的类高度耦合,因为遥控器类需要知道所有可能的动作以及如何执行这些动作。
// 遥控器调用者
class RemoteControl {private Light light;private Television television;public RemoteControl(Light light, Television television) {this.light = light;this.television = television;}public void pressButton(String button) {switch(button) {case "lightOn":light.turnOn();break;case "lightOff":light.turnOff();break;case "tvOn":television.turnOn();break;case "tvOff":television.turnOff();break;case "volumeUp":television.volumeUp();break;case "volumeDown":television.volumeDown();break;// 更多可能的按钮动作...default:System.out.println("Button " + button + " not mapped to an action.");break;}}
}// 灯光类
class Light {public void turnOn() {System.out.println("Light is On.");}public void turnOff() {System.out.println("Light is Off.");}
}// 电视类
class Television {public void turnOn() {System.out.println("Television is On.");}public void turnOff() {System.out.println("Television is Off.");}public void volumeUp() {System.out.println("Television volume turned up.");}public void volumeDown() {System.out.println("Television volume turned down.");}
}// 客户端代码
class Demo {public static void main(String[] args) {Light light = new Light();Television tv = new Television();RemoteControl remote = new RemoteControl(light, tv);remote.pressButton("lightOn");remote.pressButton("tvOn");remote.pressButton("volumeUp");// ... 更多动作}
}
请注意,虽然这种方法可以实现功能,但它违反了设计原则,如开闭原则(OCP)和单一职责原则(SRP)。每新增一个设备或者一个功能,都需要修改RemoteControl类的代码,这使得RemoteControl类随着时间推进和功能增加变得越来越庞大和难以维护。
有何问题
上述实现设计存在以下问题:
1. 高耦合: 遥控器类(RemoteControl)直接依赖于特定的设备类(如Light和Television),并且需要知道它们的接口和实现细节。这违背了设计模式中强调的依赖倒置原则,即高层模块不应该依赖于底层模块,它们都应该依赖于抽象。 2. 违反开闭原则 (OCP): 如果需要添加新的设备或者动作,例如让遥控器控制空调,就必须修改RemoteControl类的pressButton方法,添加新的case分支。开闭原则指出软件实体应该对扩展开放,对修改关闭。上述设计并不满足这一原则。 3. 违反单一职责原则 (SRP): RemoteControl类不仅是调用者,还决定了逻辑如何执行。这给了RemoteControl多个变化的原因,比如设备接口改变或者控制逻辑改变。 4. 可维护性差: 随着功能的增多,pressButton方法会变得越来越长,充满了各种case语句,这会让代码难以维护。 5. 可扩展性差: 向遥控器中添加新功能变得复杂,需要修改现有代码并有可能引入新的错误。 6. 重复代码: 如果多个按钮需要执行类似的逻辑,这就可能产生代码重复。 |
综上所述,遥控器的这种设计缺乏灵活性和可维护性。使用命令模式可以解决这些缺点,因为命令模式将请求封装成对象,与执行操作的对象解耦,增加新命令无需修改已有的代码,只需定义新的命令对象。这样增强了代码的可维护性、扩展性,且令代码更加清晰。
二、命令模式讲解
解决上述问题的方法是使用命令模式。
命令模式的定义
将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。
核心思想
将请求或操作封装成对象,并通过调用这些对象来执行操作,从而实现了客户端和接收者的解耦。 |
结构图及说明
说明
- 命令接口(Command Interface):这是一个抽象接口,定义了执行命令的通用方法。具体的命令类需要实现这个接口。
- 具体命令类(Concrete Command Classes):这些类实现了命令接口,并封装了具体的操作或请求。它们通常持有一个对接收者的引用,并实现了在调用时执行相应操作的方法。
- 接收者(Receiver):接收者对象知道如何执行与命令相关的操作。具体命令类在调用时会与接收者对象交互,执行相应的操作。
- 调用者(Invoker):调用者对象负责调用命令对象。它通常持有一个或多个命令对象的引用,并提供一个方法来执行这些命令。调用者不需要知道命令的具体实现细节,只需要调用命令对象的方法即可。
- 客户端(Client):客户端创建具体的命令对象,并将其传递给调用者对象。客户端还可以设置接收者对象,并将其传递给命令对象。客户端通过调用调用者的方法来间接执行命令。
命令模式的结构允许将请求或操作封装成独立的对象,从而实现了请求调用者和请求接收者之间的解耦。这种设计模式使得请求可以被排队、撤销、重做以及事务处理等,提高了系统的灵活性和可扩展性。同时,通过引入命令接口和具体命令类,也使得新的命令可以很容易地加入到系统中,而无需修改现有的代码。
示例代码
首先,我们需要定义一个Command接口,所有的具体命令类都需要实现这个接口:
public interface Command { void execute();
}
接下来,我们定义两个具体的命令类ConcreteCommandA和ConcreteCommandB,它们实现了Command接口:
public class ConcreteCommandA implements Command { private Receiver receiver; public ConcreteCommandA(Receiver receiver) { this.receiver = receiver; } @Override public void execute() { receiver.action(); }
} public class ConcreteCommandB implements Command { private Receiver receiver; public ConcreteCommandB(Receiver receiver) { this.receiver = receiver; } @Override public void execute() { receiver.anotherAction(); }
}
然后,我们需要定义一个Receiver类,这个类将执行实际的操作:
public class Receiver { public void action() { System.out.println("Executing action in Receiver"); } public void anotherAction() { System.out.println("Executing another action in Receiver"); }
}
接下来,我们定义一个Invoker类,这个类将负责调用命令:
public class Invoker { private Command command; public Invoker(Command command) { this.command = command; } public void setCommand(Command command) { this.command = command; } public void executeCommand() { command.execute(); }
}
最后,我们可以在客户端代码中使用这些类:
public class Client { public static void main(String[] args) { Receiver receiver = new Receiver(); Command commandA = new ConcreteCommandA(receiver); Command commandB = new ConcreteCommandB(receiver); Invoker invoker = new Invoker(commandA); invoker.executeCommand(); // 输出 "Executing action in Receiver" invoker.setCommand(commandB); invoker.executeCommand(); // 输出 "Executing another action in Receiver" }
}
在这个示例中,Command接口定义了一个execute方法,ConcreteCommandA和ConcreteCommandB类实现了这个接口,并在execute方法中调用了Receiver对象的不同方法。Invoker类持有一个Command对象,并提供了executeCommand方法来执行命令。在客户端代码中,我们创建了一个Receiver对象和两个命令对象,并使用Invoker对象来执行这些命令。
使用命令模式重构案例
假设原有的实现中包含的是一个简单的遥控器类RemoteControl,用于控制Light(开/关灯)和Television(开/关电视)两种设备。我们将使用命令模式实现它,首先定义命令接口,然后创建几个具体的命令类,之后实现调用者即遥控器类,最后实现接收者类。
- 定义命令接口 (Command):
public interface Command {void execute();
}
- 实现具体命令类 (ConcreteCommands):
// Light On Command
public class LightOnCommand implements Command {private Light light;public LightOnCommand(Light light) {this.light = light;}public void execute() {light.on();}
}// Light Off Command
public class LightOffCommand implements Command {private Light light;public LightOffCommand(Light light) {this.light = light;}public void execute() {light.off();}
}// Television On Command
public class TelevisionOnCommand implements Command {private Television television;public TelevisionOnCommand(Television television) {this.television = television;}public void execute() {television.on();}
}// Television Off Command
public class TelevisionOffCommand implements Command {private Television television;public TelevisionOffCommand(Television television) {this.television = television;}public void execute() {television.off();}
}
- 实现调用者 (Invoker):
public class RemoteControl {private Command[] onCommands;private Command[] offCommands;public RemoteControl() {onCommands = new Command[2];offCommands = new Command[2];}public void setCommand(int slot, Command onCommand, Command offCommand) {onCommands[slot] = onCommand;offCommands[slot] = offCommand;}public void pressOnButton(int slot) {onCommands[slot].execute();}public void pressOffButton(int slot) {offCommands[slot].execute();}
}
- 实现接收者 (Receivers):
// Light class
public class Light {public void on() {System.out.println("Light is on.");}public void off() {System.out.println("Light is off.");}
}// Television class
public class Television {public void on() {System.out.println("Television is on.");}public void off() {System.out.println("Television is off.");}
}
- 使用命令模式
public class Client {public static void main(String[] args) {RemoteControl remote = new RemoteControl();Light light = new Light();Television tv = new Television();Command lightOn = new LightOnCommand(light);Command lightOff = new LightOffCommand(light);Command tvOn = new TelevisionOnCommand(tv);Command tvOff = new TelevisionOffCommand(tv);remote.setCommand(0, lightOn, lightOff);remote.setCommand(1, tvOn, tvOff);// Turn on the light and tvremote.pressOnButton(0);remote.pressOnButton(1);// Turn off the light and tvremote.pressOffButton(0);remote.pressOffButton(1);}
}
这样,我们使用命令模式实现了遥控器类。添加新命令只需创建新的Command类,然后使用setCommand方法将其设为特定按钮的操作。无需修改远程控制器的内部逻辑,符合开闭原则。
克服的问题
使用命令模式实现遥控器场景能够解决的问题包括:
1. 高耦合: 在不使用命令模式的情况下,遥控器需要直接调用具体设备的操作方法,这造成了调用者和接收者之间的高耦合。使用命令模式后,遥控器只需要知道如何触发命令对象,而具体的设备操作被封装在命令对象中,降低了耦合性。 2. 开闭原则 (OCP): 开闭原则强调系统设计应该对扩展开放,对修改封闭。在命令模式中,若要引入新的命令或动作,无需修改遥控器的代码,只需要创建新的命令对象即可。这样遥控器的功能扩展不需要修改既有代码,保持了系统的开放性与封闭性。 3. 单一职责原则 (SRP): 单一职责原则要求一个类应该只有一个引起变化的原因。在命令模式中,遥控器的职责仅限于发出请求,而命令对象负责定义具体的操作行为,这样就将两者的责任区分开来,满足了SRP。 4. 可维护性: 在没有命令模式的遥控器实现中,交织的命令逻辑使得代码难以理解和维护。命令模式将命令逻辑封装在单独的对象中,使得遥控器和设备的代码更加清晰,提高了可维护性。 5. 可扩展性: 不使用命令模式,每增加一个操作或设备都可能需要修改遥控器的代码。命令模式使得增加新的命令或设备变得容易,只需定义新的命令类,无需改动遥控器或其他命令类。 6. 代码复用: 没有命令模式的遥控器实现可能会导致很多重复代码,比如多个类似设备的操作可能非常相似。命令模式提高代码复用性,因为可以通过继承或组合来复用命令类代码,从而减少重复。 |
命令模式通过对命令的抽象和封装提供了一种清晰而灵活的方式来解耦调用者和接收者,使代码变得更加模块化,易于理解、维护和扩展。
三、回顾与展望
优点
- 解耦发送者和接收者:命令模式将发起请求的对象(发送者)和执行请求的对象(接收者)分离开来。这样,发送者只需要知道如何发送请求,而不需要知道请求的具体实现细节,从而降低了系统的耦合度。
- 扩展性:当需要引入新命令时,不需要改变现有的代码,只需增加新的命令类。这符合开闭原则,对于扩展是开放的,对于修改是封闭的。
- 重用性:你可以重用这些命令,因为命令本身与其操作的上下文是独立的。
- 灵活性:命令模式可以支持撤销(undo)和重做(redo)操作,因为每个命令都能够记录它的历史状态,或者可以提供撤销其所做操作的方式。
- 可以将一组简单的命令组合成复杂的命令。
- 可以方便地实现请求的记录和队列化。
缺点
- 类膨胀:对于每一个操作都需要创建一个特定的命令类,随着应用程序命令增多,会产生大量类,使系统变得更加复杂。
- 增加复杂性:对于简单的操作,使用命令模式可能会过于复杂,它会引入许多额外的类和对象,增加了系统的复杂度。
- 性能考虑:如果在某些性能敏感的系统中,增加这样一个额外的抽象层可能会影响性能。
命令模式在需要将发起操作和执行操作解耦时表现很好,在菜单选择、队列请求、事务操作以及作业排队等场景下特别有用。然而,适当的使用是关键,因为在不需要这种级别灵活性的简单场景中,它可能会导致不必要的复杂性。
应用场景
命令模式作为一种行为设计模式,是处理请求和操作执行解耦的强大工具。以下是命令模式的一些典型应用场景:
- GUI按钮和菜单操作:图形用户界面(GUI)程序中,按钮行为和菜单命令通常使用命令模式实现。每个按钮或菜单项都有不同的行为和请求,命令模式允许将这些行为封装成具体的命令对象,使得你可以根据需要动态地为按钮分配不同的功能。
- 撤销/重做功能:在文本编辑器、图像编辑软件或数据库事务管理等应用程序里实现撤销(Undo)和重做(Redo)功能。命令对象可以用来记录发生的行为及其状态,可以在必要时回滚或重播这些行为。
- 操作队列:在需要排队多个请求并按顺序执行它们的场景中,如线程池、任务管理器或后台作业调度。命令模式可以将所有的请求封装成命令对象并添加到队列中,独立于请求本身。
- 日志请求:在需要记录和存储用户操作的系统中,可以使用命令模式记录每个操作的详细信息,当系统崩溃或出错时能够通过日志重放用户的操作以恢复到之前的状态。
- 智能家居或物联网(IoT)控制:智能家居应用中将用户的操作(如打开灯光、设置温度等)抽象为命令,这些命令可以远程或定时执行,命令模式使得新增更多功能(如新的设备控制)变得简单。
- 异步任务执行:在需要将请求处理的工作委托给后台线程执行的系统中,可以将这些请求作为命令放入工作队列中,由后台服务进行处理。
- 事务行为管理:在需要实现事务的系统中(比如需要保证一系列操作要么全部成功要么全部失败),命令对象能够用于封装所有事务的操作,并在发生错误时进行回滚。
未来展望
随着软件设计的不断进步,命令模式作为一种行为设计模式,其在分离命令的定义与调用、组织复杂命令结构等方面的优势将会保持其重要性。未来的发展趋势和可能的应用方向可从以下几个方面进行探讨:
与新兴技术的融合
命令模式很可能会与当前逐渐普及的技术像云计算、物联网(IoT)以及人工智能(AI)产生更紧密的结合。例如,在智能家居领域,命令模式可以用来设计一个集中的控制系统,用以发送和调度对各种家电的控制命令;在云服务中,命令模式可以协助构建更为灵活的服务调用机制,促进分布式系统的命令传递和执行。
可扩展性与微服务架构
随着微服务架构的流行,命令模式的可扩展性将得到进一步重视。微服务架构依赖于服务的精细化管理和交互,而利用命令模式能够有效地对服务间传递的命令进行封装处理,使得服务间的通信更加的稳定与易于维护。
丰富的行为组合与软件自动化
命令模式也可以在增强软件自动化方面发挥重要作用。由于它支持撤销、重做等操作,这使得自动化脚本或框架在执行过程中可以更灵活地控制事务。同时,命令的组合能力可以促使开发者创造出更加复杂和智能化的宏命令,这些宏命令可以应对快速变化的业务逻辑和工作流程。
增强人机交互体验
随着VR(虚拟现实)、AR(增强现实)等交互技术的发展,命令模式有潜力在未来的人机交互系统中扮演关键角色。在这些系统中,用户的各种指令可以通过命令模式进行封装,从而提供更为直观和流畅的交互体验。
面向可持续发展的软件设计
环境和可持续发展成为全球关注的热点,软件设计同样需要考虑绿色计算。命令模式由于其高度解耦命令发起者与执行者的特性,有助于构建能够轻松适应能效优化和资源管理策略的软件系统。
结语
命令模式,作为一种成熟和灵活的设计模式,对于软件工程师来说是必不可少的工具之一。随着科技的发展和计算模型的演变,命令模式的应用场景将会越发广泛,其在设计模式中的地位也将日益凸显。
继续深入学习和实践命令模式。务求不仅理解其基本概念和结构,还要通过实际项目练习来把握其精髓,灵活运用到各种复杂场景中。不断探索命令模式与其他设计模式的结合使用,也是拓宽设计思路、提升软件质量的重要途径。
记住,技术总是在变,但设计模式提供的是解决问题的思想和方法。持续学习,不断实践,让我们一同推动软件设计的边界向前延伸。
相关文章:
探索设计模式的魅力:掌握命令模式-解锁软件设计的‘遥控器’
🌈 个人主页:danci_ 🔥 系列专栏:《设计模式》 💪🏻 制定明确可量化的目标,并且坚持默默的做事。 引言:探索命令模式的奥秘 软件设计领域充满挑战与机遇,命令模式…...
LNMP搭建discuz论坛
discuz论坛是一种网络论坛软件,也称bbs,它是一种用于在互联网上建立论坛社区的程序系统。只哟中功能强大的论坛软件,可以帮助用户建立一个专业、完善的论坛社区,并且可以实现多种功能,如搭建用户注册、登录、查看主题、…...
257.【华为OD机试真题】幼儿园篮球游戏(贪心算法-JavaPythonC++JS实现)
🚀点击这里可直接跳转到本专栏,可查阅顶置最新的华为OD机试宝典~ 本专栏所有题目均包含优质解题思路,高质量解题代码(Java&Python&C++&JS分别实现),详细代码讲解,助你深入学习,深度掌握! 文章目录 一. 题目二.解题思路三.题解代码Python题解代码JAVA题解…...
[计算机网络]深度学习传输层TCP协议
💓 博客主页:从零开始的-CodeNinja之路 ⏩ 收录专栏:深度学习传输层TCP协议 🎉欢迎大家点赞👍评论📝收藏⭐文章 [计算机网络]深度学习传输层TCP协议 前提概括一: TCP协议段格式二:确认应答三:超时重传四:…...
动态头部:统一目标检测头部与注意力
摘要 在目标检测中,定位与分类相结合的复杂性导致了各种方法的蓬勃发展。以前的工作试图提高在不同的目标检测头的性能,但未能呈现一个统一的视图。在本文中,我们提出了一种新的动态头部框架来统一目标检测头部和注意力。通过在尺度感知的特…...
【状态估计】深度传感器与深度估计算法(1/3)
深度传感器与深度估计算法 深度传感器概念 获得空间中目标位置或距离的传感器,按接收的媒介波来源可分为主动式和被动式两大范畴,主动式包括激光雷达、雷达、超声波传感器等,被动式主要为单目、多目相机等,同时两大类可组合为混…...
ClickHouse从入门到精通(高级)
第1章 Explain查看执行计划 第2章 建表优化 第3章 ClickHouse语法优化规则 第4章 查询优化 第5章 数据一致性(重点) 第6章 物化视图 第7章 MaterializeMySQL引擎 第8章 常见问题排查...
什么是Docker的容器编排工具,它们之间有何不同?
随着Docker容器技术的广泛应用,容器编排工具成为了自动化部署、扩展和管理容器化应用程序的关键组件。这些工具提供了一种抽象层,帮助开发者和管理员更高效地管理大量的Docker容器,确保它们在不同的主机和环境中能够可靠地运行。目前…...
qml之Control类型布局讲解,padding属性和Inset属性细讲
1、Control布局图 2、如何理解? *padding和*Inset参数如何理解呢? //main.qml import QtQuick 2.0 import QtQuick.Controls 2.12 import QtQuick.Layouts 1.12 import QtQuick.Controls 1.4 import QtQml 2.12ApplicationWindow {id: windowvisible: …...
【Jvm】性能调优(拓展)Jprofiler如何监控和解决死锁、内存泄露问题
文章目录 Jprofiler简介1.安装及IDEA集成Jprofiler2.如何监控并解决死锁3.如何监控及解决内存泄露(重点)4.总结5.后话 Jprofiler简介 Jprofilers是针对Java开发的性能分析工具(免费试用10天), 可以对Java程序的内存,CPU,线程,GC,锁等进行监控和分析, 1.安装及IDEA集成Jprofil…...
运行错误(竞赛遇到的问题)
在代码提交时会遇见这样的错误: 此处运行错误不同于编译错误和答案错误,运行错误是指是由于在代码运行时发生错误,运行错误可能是由于逻辑错误、数据问题、资源问题等原因引起的。这些错误可能导致程序在运行时出现异常、崩溃。 导致不会显示…...
nodename nor servname provided, or not known
异常信息 在 Maven 打包过程中出现的 nodename nor servname provided, or not known 异常通常是由于 Maven 无法解析某个域名,这可能是因为网络问题、DNS 解析失败或者 Maven 配置中指定的仓库地址错误导致的。这个问题通常出现在 Maven 试图从远程仓库下载依赖时 …...
前端vue金额用逗号分隔
实现效果 代码 template部分 <el-input v-model"state.val"></el-input><div>{{ priceFor(state.val) }}</div> js部分 const state reactive({ val: });const priceFor (val)> {if(!val){return }else if(val.length<4){return…...
vulvhub-----Hacker-KID靶机
打靶详细教程 1.网段探测2.端口服务扫描3.目录扫描4.收集信息burp suite抓包 5.dig命令6.XXE漏洞读取.bashrc文件 7.SSTI漏洞8.提权1.查看python是否具备这个能力2.使用python执行exp.py脚本,如果提权成功,靶机则会开放5600端口 1.网段探测 ┌──(root…...
遨博I20协作臂关节逆解组Matlab可视化
AUBO I20协作臂关节逆解组Matlab可视化 前言1、RTB使用注意点2、代码与效果2.1、完整代码2.2、运行效果 总结 前言 注意:请预先配置好Matlab和RTB机器人工具箱环境,本文使用matlab2022b和RTB10.04版本 工作需要,使用matlab实现对六轴机械臂…...
力扣题目训练(15)
2024年2月8日力扣题目训练 2024年2月8日力扣题目训练507. 完美数520. 检测大写字母521. 最长特殊序列 Ⅰ221. 最大正方形237. 删除链表中的节点115. 不同的子序列 2024年2月8日力扣题目训练 2024年2月8日第十五天编程训练,今天主要是进行一些题训练,包括…...
PCB差模辐射是如何产生的
在电路应用中,高频时钟信号往往会采用差分线传输模式,其优点是在提高速率的同时减小功耗和提高抗扰度,因此,差模辐射就成为电路正常工作的结果,是电流流过导体形成的环路所产生,差模辐射模型可以被模拟为一个小环形天线,对于一个面积为A的小环路,载有电流Idm,在远场中…...
车载诊断协议DoIP系列 —— 协议中术语解释和定义
车载诊断协议DoIP系列 —— 协议中术语解释和定义 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师(Wechat:gongkenan2013)。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 本就是小人物,输了就是输了,不要在意别人怎么看自己。江湖一碗茶,…...
【退役之重学前端】关于在控制台得到undefined的事
在浏览器控制台中,undefined 会时不时地,在我不想看到的地方出现。如果你遇到相同的问题,在这篇博客中你会得到答案。 先来看代码块 function test(){} test()//undefined再看下一个代码块 function test(){return 1; } test()//1再来看一个…...
指数和估计六大问题
1955年英国著名数学家R.A.Rankin在牛津大学出版的数学刊物Quart.J.Math.发表了论文(现 FRS D.R.Heath-Brown为主编),专门讲van der Corput方法产生的指数对理论(1933年E.Phillips提出的精彩理论,好友曲阜师范大学毕业中…...
【软件相关】基于Alist挂载云盘到本地文件资源管理器
文章目录 0 前言1 Alist挂载云盘2 RaiDrive配置3 rclone配置 0 前言 因为最近在研究各种云盘存储影视资源的方法,无意间看到一个教程是利用软件将云盘挂载到本地的资源管理器,这样就能实现类似本地文件操作的方式来操作云盘文件,还是有点意思…...
Java多线程系列——锁
0.引言 在并发编程中,锁是一种重要的同步机制,用于控制对共享资源的访问。Java 提供了多种锁的实现,每种锁都有不同的特性和适用场景。本文将深入介绍 Java 中常见的锁类型,包括内置锁、显式锁、读写锁等,并讨论它们的…...
蓝牙BLE学习-GAP
1.概述 GAP层(Generic access profile-通用访问配置文件)。GAP是对LL层payload(有效数据包)如何进行解析的两种方式的一种,而且也是最简单的一种。GAP简单的对LL payload进行一些规范和定义,因此GAP能实现的…...
算法训练营day28(补), 贪心算法2
//122. 买卖股票的最佳时机 II func maxProfit(prices []int) int { result : 0 //利润总和 for i : 1; i < len(prices); i { if prices[i]-prices[i-1] > 0 { result result (prices[i] - prices[i-1]) } } return result } //55. 跳跃游戏 func canJump(nums []…...
Vue核心基础4:绑定样式、条件渲染、列表渲染
1 绑定样式 【代码】 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>绑定样式</title><s…...
go-zero读取mysql部分字段
读取部分字段,使用函数 QueryRowPartialCtx 。 假设有如下一张表: CREATE TABLE test (id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, ctime DATETIME);要读取字段 ctime 值。 定义一结构体: type X struct {state int db:"…...
反转一个单链表
反转一个单链表 题意:反转一个单链表。 示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL 思路 需要虚拟节点么? 答:不需要,因为没有删除节点,只是改变了节点的指向。 遍…...
拿捏c语言指针(中)
前言 书接上回 拿捏c语言指针(上) 此篇主要讲解的是指针与数组之间的爱恨情仇,跟着我的脚步一起来看看吧~ 创造不易,可以帮忙点点赞吗 如有差错,欢迎指出 理解数组名 数组名是首元素地址 例外 1.sizeof࿰…...
鸿蒙语言ArkTS(更好的生产力与性能)
ArkTS是鸿蒙生态的应用开发语言 ArkTS提供了声明式UI范式、状态管理支持等相应的能力,让开发者可以以更简洁、更自然的方式开发应用。 同时,它在保持TypeScript(简称TS)基本语法风格的基础上,进一步通过规范强化静态检…...
VBA技术资料MF120:打印固定标题行列
我给VBA的定义:VBA是个人小型自动化处理的有效工具。利用好了,可以大大提高自己的工作效率,而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套,分为初级、中级、高级三大部分,教程是对VBA的系统讲解&#…...
MongoDB聚合运算符:$add
$add运算符将将数字相加或将数字和日期相加。如果参数之一是日期,则 $add会将其他参数视为毫秒,并添加到日期中。 语法 { $add: [ <expression1>, <expression2>, ... ] }参数可以是任何有效的表达式,只要能否解析为数值或日期…...
《剑指Offer》笔记题解思路技巧优化 Java版本——新版leetcode_Part_4
《剑指Offer》笔记&题解&思路&技巧&优化_Part_4 😍😍😍 相知🙌🙌🙌 相识😢😢😢 开始刷题1. LCR 148. 验证图书取出顺序——栈的压入、弹出序列2. LCR 14…...
数据库第四次实验
目录 1.建立数据表并插入数据 2 视图的创建 2.1 行列子集视图的创建 2.2 多表视图 2.3视图上建立视图 2.4分组视图 2.5带表达式的视图 3 删除视图 4 查询视图 5 更新视图 5.1 修改某一个属性 5.2 删除一条数据 5.3 插入…...
基于PPNSA+扰动算子的车间调度最优化matlab仿真,可以任意调整工件数和机器数,输出甘特图
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 基于PPNSA扰动算子的车间调度最优化matlab仿真,可以任意调整工件数和机器数,输出甘特图和优化收敛曲线。 2.测试软件版本以及运行结果展示 MATLAB2022a版本运行…...
UnityShader——06UnityShader介绍
UnityShader介绍 UnityShader的基础ShaderLab UnityShader属性块介绍 Properties {//和public变量一样会显示在Unity的inspector面板上//_MainTex为变量名,在属性里的变量一般会加下划线,来区分参数变量和临时变量//Texture为变量命名//2D为类型&…...
人工智能学习与实训笔记(一):零基础理解神经网络
人工智能专栏文章汇总:人工智能学习专栏文章汇总-CSDN博客 本篇目录 一、什么是神经网络模型 二、机器学习的类型 2.1 监督学习 2.2 无监督学习 2.3 半监督学习 2.4 强化学习 三、网络模型结构基础 3.1 单层网络 编辑 3.2 多层网络 3.3 非线性多层网络…...
LeetCode刷题小记 一、【数组】
LeetCode刷题小记 一、【数组】 文章目录 LeetCode刷题小记 一、【数组】写在前面1. 数组1.1 理论基础1.2 二分查找1.3 移除元素1.4 有序数组的平方1.5 长度最小的子数组1.6 螺旋矩阵II Reference 写在前面 本系列笔记主要作为笔者刷题的题解,所用的语言为Python3&…...
iOS总体框架介绍和详尽说明
iOS是由苹果公司开发的移动操作系统,为iPhone、iPad、iPod Touch等设备提供支持。iOS采用了基于Unix的核心(称为Darwin),并采用了类似于Mac OS X的图形用户界面。以下是iOS的总体框架介绍和详尽说明: UIKit框架&#…...
【C++】const与constexpr详解
1. constexpr:常量表达式 所谓常量表达式,指的就是由多个(≥1)常量组成的表达式。换句话说,如果表达式中的成员都是常量,那么该表达式就是一个常量表达式。这也意味着,常量表达式一旦确定,其值将无法修改。 实际开发中,我们经常会…...
蓝桥杯:日期统计讲解(C++)
日期统计 本题来自于:2023年十四届省赛大学B组真题 主要考察:暴力。 代码放在下面,代码中重要的细节全都写了注释,非常清晰明了: #include <bits/stdc.h> //万能头文件 using namespace std;int main() {…...
Python re.findall()中的正则表达式包含多个括号时的返回值——包含元组的列表
当re.findall()中的正则表达式包含多个括号时,返回值是一个列表,其中每个元素都是一个元组。这个元组的长度与正则表达式中括号的数量相同,元组中的每个元素都是与相应括号中的模式匹配的文本。 import re # 定义一个包含三个括号的正则表达…...
Python——列表
一、列表的特性介绍 列表和字符串⼀样也是序列类型的数据 列表内的元素直接⽤英⽂的逗号隔开,元素是可变的,所以列表是可变的数据类型,⽽字符串不是。 列表的元素可以是 Python 中的任何类型的数据对象。如:字符串、…...
无人机图像识别技术研究及应用,无人机AI算法技术理论,无人机飞行控制识别算法详解
在现代科技领域中,无人机技术是一个备受瞩目的领域。随着人们对无人机应用的需求在不断增加,无人机技术也在不断发展和改进。在众多的无人机技术中,无人机图像识别技术是其中之一。 无人机图像识别技术是利用计算机视觉技术对无人机拍摄的图像…...
清华AutoGPT:掀起AI新浪潮,与GPT4.0一较高下
引言: 随着人工智能技术的飞速发展,自然语言处理(NLP)领域迎来了一个又一个突破。最近,清华大学研发的AutoGPT成为了业界的焦点。这款AI模型以其出色的性能,展现了中国在AI领域的强大实力。 目录 引言&…...
人工智能学习与实训笔记(二):神经网络之图像分类问题
人工智能专栏文章汇总:人工智能学习专栏文章汇总-CSDN博客 目录 二、图像分类问题 2.1 尝试使用全连接神经网络 2.2 引入卷积神经网络 2.3 分类函数Softmax 2.4 交叉熵损失函数 2.5 学习率优化算法 2.6 图像预处理算法 2.6.1 随机改变亮暗、对比度和颜色等 …...
SSM框架,spring-aop的学习
代理模式 二十三种设计模式中的一种,属于结构型模式。它的作用就是通过提供一个代理类,让我们在调用目标方法的时候,不再是直接对目标方法进行调用,而是通过代理类间接调用。让不属于目标方法核心逻辑的代码从目标方法中剥离出来…...
【设计模式】4、策略模式
文章目录 一、问题二、解决方案2.1 真实世界的类比2.2 策略模式结构2.3 适用场景2.4 实现方式2.5 优缺点2.6 与其他模式的关系 三、示例代码3.1 go3.2 rust 策略模式是一种行为设计模式,它能定义一系列算法,把每种算法分别放入独立的类中,以是…...
【C++学习手札】多态:掌握面向对象编程的动态绑定与继承机制(深入)
🎬慕斯主页:修仙—别有洞天 ♈️今日夜电波:世界上的另一个我 1:02━━━━━━️💟──────── 3:58 🔄 ◀️ ⏸ ▶️ ☰ &am…...
【机构vip教程】Android SDK手机测试环境搭建
Android SDK 的安装和环境变量的配置 前置条件:需已安装 jdk1.8及 以上版本 1、下载Android SDK,解压后即可(全英文路径);下载地址:http://tools.android-studio.org/index.php/sdk 2、新建一个环境变量&…...
2024.2.18
使用fgets统计给定文件的行数 #include<stdio.h> #include<string.h> int main(int argc, const char *argv[]) {FILE *fpNULL;if((fpfopen("./test.txt","w"))NULL){perror("open err");return -1;}fputc(h,fp);fputc(\n,fp);fput…...