命令模式

article/2025/10/20 17:15:20

一、命令模式介绍

       在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个。我们只需要在程序运行时指定具体的请求接收者即可,此时可以使用命令模式来设计。

       命令模式使得请求发送者与请求接收者消除彼此之间的耦合,让对象之间的调用关系更加灵活,实现解耦。在命令模式中,会将一个请求封装为一个对象,以便使用不同参数来表示不同的请求,同时命令模式也支持撤销的操作。通俗易懂的理解:将军发布命令,士兵去执行。其中有几个角色:将军(命令发布者)、士兵(命令的具体执行者)、命令(连接将军和士兵)。

二、命令模式的原理类图

命令模式的原理类图如下所示:

说明:

1)Involer:是调用者角色

2)Command:是命令角色,需要执行的所有命令都在这里,可以是接口或抽象类

3)Receiver:接受者角色,知道如何实施和执行一个请求相关的操作

4)ConcreteCommand:将一个接受者对象与一个动作绑定,调用接受者相应的操作。实现execute

三、命令模式例子

       实现智能生活项目需求:1)我们买了一套智能家电,有照明灯、风扇、冰箱、洗衣机,我们只要在手机上安装app就可以控制对这个家电工作;2)这些智能家电来自不同的厂家,我们不想针对每一种家电都安装一个app分别控制,我们希望只要一个app就可以控制全部智能家电;3)要实现一个app控制所有智能家电的需要,则每个智能家电厂都要提供一个统一的接口给app调用,这时就可以考虑使用命令模式;4)在我们的例子中,动态的请求者是手机app,动作的执行者是每个厂商的一个家电产品。

类图如下所示:

代码如下所示:

创建Command接口及其相应子类:

//创建命令接口
public interface Command{//执行动作(操作)void execute();//撤销动作(操作)void undo();
}
public class LightOnCommand implements Command{//聚合LightReceiverprivate LightReceiver receiver;public LightOnCommand(LightReceiver receiver){this.receiver = receiver;}public void execute(){receiver.on();}public void undo(){receiver.off();}
}
public class LightOffCommand implements Command{//聚合LightReceiverprivate LightReceiver receiver;public LightOnCommand(LightReceiver receiver){this.receiver = receiver;}public void execute(){receiver.off();}public void undo(){receiver.undo();}
}
//没有任何命令,即空执行:用于初始化每个按钮,当调用空命令时,对象什么都不做
//其实这是一种设计模式,可以省掉对空判断
public class NoCommand implements Command{public void execute(){}public void undo(){}
}

创建LightReceiver类:

public class LightReceiver{public void on(){System.out.println("电灯打开...");}public void off(){System.out.println("电灯关闭...");}
}

创建RemoteController类:

public class RemoteController{private Command[] onCommands;private Command[] offCommands;private Command undoCommand;//构造器,完成对按钮初始化public RemoteController(){onCommands = new Command[5];offCommands = new Command[5];for(int i = 0; i < 5; i++){onCommands[i] = new NoCommand();offCommands[i] = new NoCommand();}}//给按钮设置你需要的命令public void setCommand(int no, Command onCommand, Command offCommand){onCommands[on] = onCommand;offCommands[on] = offCommand;}//按下开按钮public void onButtonWasPushed(int no){//找到你按下的开的按钮,并调用对应方法onCommands[no].execute();//记录这次的操作,用于撤销undoCommand = onCommands[no]}//按下撤销按钮public void undoButtonWasPushed(){undoCommand.undo();}
}

创建Client类:

public class Client{public static void main(String[] args){//使用命令设计模式,完成通过遥控器对电灯的操作//创建电灯的对象(接受者)LightReceiver lightReceiver = new LightReceiver();//创建电灯相关的开关命令LightOnCommand on = new LightOnCommand(lightReceiver);LightOffCommand off = new LightOffCommand(lightReceiver);//需要一个遥控器RemoteController remoteController = new RemoteController();//给遥控器设置命令remoteController.setCommand(0, on ,off);System.out.println("--------按下灯的开按钮-------");remoteController.onButtonWasPushed(0);System.out.println("--------按下灯的关按钮-------");remoteController.offButtonWasPushed(0); System.out.println("--------按下灯的撤销按钮-------");remoteController.undoButtonWasPushed(); }
}

四、命令模式的注意事项和细节

1)将发起请求的对象与执行请求的对象解耦。发起请求的对象是调用者,调用者只要调用命令对象的execute()方法就可以让接收者工作,而不必知道具体的接收者对象是谁,如何实现的。命令对象会负责让接收者执行请求的动作,也就是说:请求发起者和请求执行者之间的解耦过程是通过命令对象实现的,命令对象起到了纽带桥梁的作用

2)容易设计一个命令队列,只要把命令对象放到列队,就可以多线程的执行命令

3)容易实现对请求的撤销和重做

4)命令模式不足:可能导致某些系统有过多的具体命令类,增加了系统的复杂度,这点在使用的时候要注意

5)空命令也是一种设计模式,它为我们省去了判空的操作,在上面的实际中,如果没有用空命令,我们每按下一个按键就要判空,这给我们编码带来一定的麻烦

6)命令模式经典的应用场景:界面的一个按钮都是一条命令,模拟CMD订单的撤销/恢复、触发-反馈机制


http://chatgpt.dhexx.cn/article/9XG1iWA2.shtml

相关文章

Java设计模式——命令模式

文章目录 命令模式 命令模式 命令模式很好理解&#xff0c;举个例子&#xff0c;司令员下令让士兵去干件事情&#xff0c;从整个事情的角度来考虑&#xff0c;司令员的作用是&#xff0c;发出口令&#xff0c;口令经过传递&#xff0c;传到了士兵耳朵里&#xff0c;士兵去执行…

如何设置IPv4和IPv6报文的DSCP值——网络测试仪实操

一、操作说明 在QoS测试中&#xff0c;经常要设置不同优先级的报文&#xff0c;来验证被测设备对于优先级的调度。所以&#xff0c;我们就要了解如何设置IPv6和IPv6报文中的DSCP&#xff08;大部分使用DSCP值&#xff0c;也会用到TOS值&#xff09; 这里我们使用测试接交换机&…

DSCP vs IPv4 Tos

首先看IPv4包头如下 其中&#xff0c;Qos用到的是Tos定义有下面两种&#xff1a; 老的IPv4 TOS Byte定义和值 新的DSCP定义和值 DSCP值 DSCP ValueMeaningDrop ProbabilityEquivalent IP Precedence Value101 110 (46)High Priority Expedited Forwarding (EF)N/A101 – …

c语言socket设置IPV4/6的dscp值

环境&#xff1a;linux centos7 、x86 、UDP包 使用sock需要增加头文件 #include <sys/socket.h> #include <sys/types.h> 设置方法很简单&#xff0c;都是使用setsockopt函数&#xff0c;就是找资料及如何太麻烦&#xff0c;尤其是IPV6。需要注意IPV4设置的是I…

tos cos dscp 区别和作用

tos cos 和dscp 都是通过iptable 的mange 的mark 标签来更改的。 谈到qos首先需要了解qos调度的几个重要过程,qos调度过程包括网络入口数据流量的分类和标记、骨干网设备上的拥塞避免和拥塞管理、网路出口的队列调度这几个重要过程. 1、cos和tos的区别: 通过acl对流量进行分类以…

IP优先级和DSCP之间的关系

1. IP优先级和DSCP之间的关系 DiffServ体系定义的DS字段&#xff0c;取代IPv4中ToS字段作出有关数据包分类和流量调节功能的策略。 1.1. ToS字段 在IPv4的报文头中&#xff0c;TOS字段是1字节&#xff0c;根据RFC1122的定义&#xff0c;IP优先级&#xff08;IPPrecedence&…

802.1P优先级、IP优先级、TOS优先级及DSCP优先级的分类和对应

1、802.1P优先级&#xff08;有时也称COS优先级&#xff09;&#xff1a; 802.1p用户优先级定义在二层802.1Q 标签头中的TCI字段中。&#xff0c;和VLAN ID一起使用&#xff0c;位于高位起16-18bit字段&#xff0c;长度3bit&#xff0c;取值范围0-7&#xff0c;0优先级最低&…

DSCP 与IP 优先级IP优先级

首先看IPv4包头如下 其中&#xff0c;Qos用到的是Tos定义有下面两种&#xff1a; 老的IPv4 TOS Byte定义和值 新的DSCP定义和值 DSCP值 DSCP Value Meaning Drop Probability Equivalent IP Precedence Value 101 110 (46) High Priority Expedited Forwarding (EF) N/A…

IP Precedence、DSCP、TOS

刚开始接触QoS时&#xff0c;经常会被IP Precedence、DSCP、TOS这些名词搞迷糊&#xff0c;那么接下来就梳理一下。 首先 IP Precedence IPv4中有8bit作为TOS字段&#xff0c;一开始RFC791定义了TOS前三位为IP Precedence&#xff0c;划分了8个优先级&#xff0c;可用于流分类…

【网络】Cos和ToS和DSCP|Qos|PHB的含义和区别以及映射

目录 视频教程&#xff1a; 介绍和区别 Qos/Cos IP-TOS&#xff08;IPP/CS&#xff09;和DSCP PHB&#xff08;Per-Hop-Behaviors&#xff09; 区别 各个等级的DSCP值和含义(PHB) 映射 COS到DSCP的映射 IP-Precedence到DSCP的映射&#xff08;Tos-->DSCP&#xff09…

TOS 和DSCP

IPv4报文中有三种承载QoS优先级标签的方式&#xff0c;分别为基于二层的CoS字段&#xff08;IEEE802.1p&#xff09;的优先级、基于IP层的IP优先级&#xff08;IP Precedence&#xff09;字段ToS优先级和基于IP层的DSCP&#xff08;Differentiated Services Codepoint&#xff…

什么是DSCP,如何使用DSCP标记搭配ROS策略

什么是DSCP&#xff0c;如何使用DSCP标记搭配ROS策略 一、什么是DSCP DSCP&#xff1a;差分服务代码点&#xff08;Differentiated Services Code Point&#xff09;&#xff0c;IETF于1998年12月发布了Diff-Serv&#xff08;Differentiated Service&#xff09;的QoS分类标准…

TOS 和 DSCP理解

背景 IPv4报文中有三种承载QoS优先级标签的方式&#xff0c;分别为基于二层的CoS字段&#xff08;IEEE802.1p&#xff09;的优先级、基于IP层的IP优先级&#xff08;IP Precedence&#xff09;字段ToS优先级和基于IP层的DSCP&#xff08;Differentiated Services Codepoint&am…

谈谈ES5和ES6的区别

我们都知道JavaScript是由三部分组成&#xff1a; 1. ECMAScript(核心)&#xff1a;规定了语言的组成部分>语法、类型、语句、关键字、保留字、操作符、对象 2. BOM(浏览器对象模型): 支持访问和操作浏览器窗口&#xff0c;可以控制浏览器显示页面以外的部分。 3. DOM(文…

ES5基础语法

一.类与对象 class father {that this;constructor(uname, age) {this.uname uname;this.age age;}sing(song) {console.log(this.uname song);}}class son extends father {constructor(uname,age) {super(uname,age);this.unameuname;this.age age;}sing(song){console.…

ES5语法

从今天起&#xff0c;我们开始接触JS部分&#xff0c;先从ES5一些简单的语法入手。下面先看下思维导图&#xff0c;确定我们的学习思路&#xff1a; 今天我们先学习代码规范&#xff0c;数据类型以及数据类型转换三个模块 代码规范 JS中的一切都区分大小写 标识符&#xff1…

es5 es6 互相转换

- 工具&#xff1a;Visual Studio Code - 具体过程 1.新建项目&#xff0c;dist存放ES6格式的&#xff0c;src存放ES5格式的&#xff0c;如下 index.html内容&#xff0c;此处引用dist中的js 2.打开终端&#xff08;ctrl &#xff09; npm需要安装&#xff0c;安装node即可…

套接字

套接字&#xff08;socket&#xff09;最早是由BSD在1982年引入的通信机制&#xff0c;目前已被广泛移植到主流的操作系统中。对于应用开发人员来说&#xff0c;套接字&#xff08;socket&#xff09;是一种特殊的I/O接口&#xff0c;也是一种文件描述符。socket是一种常用的进…

原始套接字简介

一 原始套接字概述 原始套接字&#xff0c;指在传输层下面使用的套接字。流式套接字和数据报套接字这两种套接字工作在传输层&#xff0c;主要为应用层的应用程序提供服务&#xff0c;并且在接收和发送时只能操作数据部分&#xff0c;而不能对IP首部或TCP和UDP首部进行操作&am…

网络套接字编程(socket 详解)

socket 编程 套接字概念 Socket本身有“插座”的意思&#xff0c;在Linux环境下&#xff0c;用于表示进程间网络通信的特殊文件类型。本质为内核借助缓冲区形成的伪文件。既然是文件&#xff0c;那么理所当然的&#xff0c;我们可以使用文件描述符引用套接字。与管道类似的&a…