探索设计模式的魅力:掌握命令模式-解锁软件设计的‘遥控器’
🌈 个人主页: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提出的精彩理论,好友曲阜师范大学毕业中…...

eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)
说明: 想象一下,你正在用eNSP搭建一个虚拟的网络世界,里面有虚拟的路由器、交换机、电脑(PC)等等。这些设备都在你的电脑里面“运行”,它们之间可以互相通信,就像一个封闭的小王国。 但是&#…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

云原生玩法三问:构建自定义开发环境
云原生玩法三问:构建自定义开发环境 引言 临时运维一个古董项目,无文档,无环境,无交接人,俗称三无。 运行设备的环境老,本地环境版本高,ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...
Python 包管理器 uv 介绍
Python 包管理器 uv 全面介绍 uv 是由 Astral(热门工具 Ruff 的开发者)推出的下一代高性能 Python 包管理器和构建工具,用 Rust 编写。它旨在解决传统工具(如 pip、virtualenv、pip-tools)的性能瓶颈,同时…...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...
React---day11
14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store: 我们在使用异步的时候理应是要使用中间件的,但是configureStore 已经自动集成了 redux-thunk,注意action里面要返回函数 import { configureS…...

android13 app的触摸问题定位分析流程
一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...

Ubuntu系统多网卡多相机IP设置方法
目录 1、硬件情况 2、如何设置网卡和相机IP 2.1 万兆网卡连接交换机,交换机再连相机 2.1.1 网卡设置 2.1.2 相机设置 2.3 万兆网卡直连相机 1、硬件情况 2个网卡n个相机 电脑系统信息,系统版本:Ubuntu22.04.5 LTS;内核版本…...