设计模式:命令模式(C#、JAVA、JavaScript、C++、Python、Go、PHP)

news2024/11/17 1:32:15

简介:

命令模式,它是一种行为型设计模式,它尝试将请求或操作封装成对象,从而降低系统的耦合度,增加系统的可扩展性,并支持撤销、重做、事务等功能。

在命令模式中,请求被封装为一个独立的对象,称为命令。命令对象包含请求的接收者和对接收者的操作。请求者通过调用命令对象的执行方法来发送请求,接收者则负责执行命令。

命令模式包括以下角色:

命令(Command):封装了一次请求,包括请求的接收者和对接收者的操作。
接收者(Receiver):真正执行命令操作的对象。
请求者(Invoker):负责向命令对象发起请求,并将命令对象设置为接收者的命令。
客户端(Client):创建请求者、命令和接收者对象,并将它们组装起来。

命令模式的使用场景:
1、当系统的某项操作具备命令语义,且命令实现不稳定(变化)时,可以通过命令模式解耦请求与实现。使用抽象命令接口使请求方的代码架构稳定,封装接收方具体命令的实现细节。接收方与抽象命令呈现弱耦合(内部方法无需一致),具备良好的扩展性。
2、当请求调用者需要与请求接收者解耦时,命令模式可以使调用者和接收者不直接交互。
3、系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作时,可以使用命令模式。
4、系统需要在不同的时间指定请求、将请求排队和执行请求时,可以使用命令模式。
5、系统需要执行一组操作时,命令模式可以定义宏命令来实现该功能。

总之,命令模式适用于那些需要将请求和操作封装成对象,降低系统的耦合度,增加系统的可扩展性,并支持撤销、重做、事务等功能的情况。

命令模式的创建步骤:
1、定义接收者类(Receiver),包含执行命令所需要的具体操作。
2、定义命令接口(Command),包含执行命令的方法。
3、创建具体命令类(ConcreteCommand),实现命令接口,并接受接收者作为参数,实现具体命令。
4、创建接收者类,接受具体命令作为参数,实现具体命令。
5、创建请求者类(Invoker),包含执行命令的方法,该方法接受具体命令作为参数。
6、在请求者类中调用具体命令的执行方法,将接收者作为参数传递给具体命令。
7、在客户端中创建请求者对象和具体命令对象,并将它们组装起来。

以上步骤是创建命令模式的基本步骤,可以根据具体情况进行适当的修改和扩展。

命令模式的优点,主要包括:
1、请求发送者和接收者解耦:通过引入中间件(抽象接口)降低系统的耦合度,请求发送者不直接与接收者交互,请求发送者只需要知道如何执行命令,而不需要了解命令的具体实现。
2、支持撤销和重做:命令模式可以容易地实现撤销和重做操作,因为每个命令都可以实现自己的撤销和重做逻辑。
3、事务支持:命令模式可以支持事务操作,即一系列命令的组合,如果其中一个命令执行失败,可以撤销整个事务。
4、命令的参数化:命令模式可以将命令封装成对象,并使用参数来传递数据,从而方便地对命令进行定制和扩展。
5、命令的队列化:命令模式可以较容易地设计一个命令队列,从而按照一定的顺序执行命令。
6、降低类的耦合度:命令模式把请求一个操作的对象与知道怎么执行一个操作的对象分割开,可以让类的单一职责更明确,充分解耦。
7、方便添加新命令:由于加进新的具体命令类不影响其它的类,因此增加新的具体命令类很容易。

命令模式的缺点,主要包括:
1、可能产生大量具体命令类:为了支持各种命令,需要定义大量的具体命令类,这会增加系统的复杂度和维护成本。
2、请求调用者和接收者仍然存在一定的耦合:虽然命令模式使得请求调用者和接收者解耦,但它们仍然存在一定的耦合关系,因为请求调用者需要知道接收者的存在以及如何调用接收者的方法。
3、实现复杂度较高:命令模式需要定义抽象命令接口和具体命令类,以及实现撤销和恢复等功能,实现起来较为复杂。
4、对事务的支持可能不完整:虽然命令模式可以支持事务操作,但对于复杂的事务支持可能不完整,需要额外设计。

示例:

一、C#命令模式

以下是一个示例,展示了如何在C#中实现命令模式:

// 定义命令接口  
public interface ICommand  
{  
    void Execute();  
    void Undo();  
}  
  
// 定义具体命令类  
public class ConcreteCommand : ICommand  
{  
    private Receiver receiver;  
  
    public ConcreteCommand(Receiver receiver)  
    {  
        this.receiver = receiver;  
    }  
  
    public void Execute()  
    {  
        receiver.Operation();  
    }  
  
    public void Undo()  
    {  
        receiver.Undo();  
    }  
}  
  
// 定义接收者类  
public class Receiver  
{  
    public void Operation()  
    {  
        // 执行操作  
    }  
  
    public void Undo()  
    {  
        // 撤销操作  
    }  
}  
  
// 定义请求者类  
public class Invoker  
{  
    private ICommand command;  
  
    public void SetCommand(ICommand command)  
    {  
        this.command = command;  
    }  
  
    public void ExecuteCommand()  
    {  
        command.Execute();  
    }  
}

在客户端代码中,可以创建具体命令对象和请求者对象,并将它们组装起来,然后通过请求者对象来执行命令。

public class Client
{
    public void Test(){
        Receiver receiver = new Receiver(); // 创建接收者对象  
        ConcreteCommand command = new ConcreteCommand(receiver); // 创建具体命令对象,并传入接收者对象作为参数  
        Invoker invoker = new Invoker(); // 创建请求者对象  
        invoker.SetCommand(command); // 将具体命令对象设置给请求者对象作为属性使用、回调或引用,从而实现请求者和具体命令对象的解耦。这样客户端代码只需要与请求者对象交互即可执行命令。
    }
}

二、java命令模式

命令模式通常通过以下方式实现:

interface Command {  
    void execute();  
    void undo();  
}  
  
class ConcreteCommand implements Command {  
    private Receiver receiver;  
  
    public ConcreteCommand(Receiver receiver) {  
        this.receiver = receiver;  
    }  
  
    @Override  
    public void execute() {  
        receiver.operation();  
    }  
  
    @Override  
    public void undo() {  
        receiver.undo();  
    }  
}  
  
class Receiver {  
    public void operation() {  
        // 执行操作  
    }  
  
    public void undo() {  
        // 撤销操作  
    }  
}  
  
class Invoker {  
    private Command command;  
  
    public void setCommand(Command command) {  
        this.command = command;  
    }  
  
    public void executeCommand() {  
        command.execute();  
    }  
}

public class Demo {  
    public static void main(String[] args) {  
        Receiver receiver = new Receiver(); // 创建接收者对象  
        ConcreteCommand command = new ConcreteCommand(receiver); // 创建具体命令对象,并传入接收者对象作为参数  
        Invoker invoker = new Invoker(); // 创建请求者对象  
        invoker.setCommand(command); // 将具体命令对象设置给请求者对象作为属性使用、回调或引用,从而实现请求者和具体命令对象的解耦。这样客户端代码只需要与请求者对象交互即可执行命令。
    }
}

三、javascript命令模式

在JavaScript中,命令实现方式如下:

class Command {  
  constructor(executor) {  
    this.executor = executor;  
  }  
  
  execute() {  
    this.executor();  
  }  
}  
  
function executeCommand(command) {  
  command.execute();  
}  
  
function greet() {  
  console.log('Hello, World!');  
}  
  
const greetCommand = new Command(greet);  
executeCommand(greetCommand); // 输出:Hello, World!

在上面的代码中,我们定义了一个Command类,它接受一个执行器函数作为构造函数的参数。执行器函数是在Command对象被调用时执行的函数。我们还定义了一个executeCommand函数,它接受一个Command对象作为参数,并调用其execute方法来执行命令。最后,我们创建了一个greet函数作为执行器函数,并将其传递给Command构造函数来创建一个greetCommand对象。然后,我们调用executeCommand函数并将greetCommand对象作为参数传递给它,从而执行了greet函数。

通过将函数或方法封装成对象,我们可以将其传递给其他函数或方法,以便在不同的上下文中使用。这种模式可以用于实现撤销操作、事务处理、日志记录等功能。

四、C++命令模式

以下是在C++中实现命令模式:

class Command {  
public:  
    virtual ~Command() {}  
    virtual void execute() = 0;  
    virtual void undo() = 0;  
};  
  
class ConcreteCommand : public Command {  
public:  
    ConcreteCommand(Receiver* receiver) : m_receiver(receiver) {}  
    void execute() override {  
        m_receiver->operation();  
    }  
    void undo() override {  
        m_receiver->undo();  
    }  
private:  
    Receiver* m_receiver;  
};  
  
class Receiver {  
public:  
    void operation() {  
        // 执行操作  
    }  
    void undo() {  
        // 撤销操作  
    }  
};  
  
class Invoker {  
public:  
    Invoker(Receiver* receiver) : m_receiver(receiver) {}  
    void setCommand(Command* command) {  
        m_command = command;  
    }  
    void executeCommand() {  
        m_command->execute();  
    }  
    void undoCommand() {  
        m_command->undo();  
    }  
private:  
    Command* m_command;  
    Receiver* m_receiver;  
};

int main() {
    Receiver* receiver = new Receiver(); // 创建接收者对象  
    ConcreteCommand* command = new ConcreteCommand(receiver); // 创建具体命令对象,并传入接收者对象作为参数  
    Invoker* invoker = new Invoker(command); // 创建请求者对象,并将具体命令对象传递给请求者对象作为属性使用、回调或引用,从而实现请求者和具体命令对象的解耦。这样客户端代码只需要与请求者对象交互即可执行命令。
}

五、python命令模式

以下是在python中实现命令模式:

class Command:  
    def execute(self):  
        pass  
      
    def undo(self):  
        pass  
  
class ConcreteCommand(Command):  
    def __init__(self, receiver):  
        self.receiver = receiver  
      
    def execute(self):  
        self.receiver.operation()  
      
    def undo(self):  
        self.receiver.undo()  
  
class Receiver:  
    def operation(self):  
        print("Operation executed")  
      
    def undo(self):  
        print("Operation undone")  
  
class Invoker:  
    def __init__(self):  
        self.command = None  
      
    def set_command(self, command):  
        self.command = command  
      
    def execute_command(self):  
        self.command.execute()  
  
if __name__ == "__main__":  
    receiver = Receiver()  
    command = ConcreteCommand(receiver)  
    invoker = Invoker()  
    invoker.set_command(command)  
    invoker.execute_command()  # Output: Operation executed

六、go命令模式

以下是一个示例,展示了如何在go中实现命令模式:

type Command interface {  
    Execute()  
    Undo()  
}  
  
type ConcreteCommand struct {  
    receiver Receiver  
}  
  
func (c *ConcreteCommand) Execute() {  
    c.receiver.Operation()  
}  
  
func (c *ConcreteCommand) Undo() {  
    c.receiver.Undo()  
}  
  
type Receiver struct {}  
  
func (r *Receiver) Operation() {  
    fmt.Println("Operation executed")  
}  
  
func (r *Receiver) Undo() {  
    fmt.Println("Operation undone")  
}  
  
type Invoker struct {  
    command Command  
}  
  
func (i *Invoker) SetCommand(cmd Command) {  
    i.command = cmd  
}  
  
func (i *Invoker) ExecuteCommand() {  
    i.command.Execute()  
}
func main() {  
    receiver := &Receiver{}   // 创建接收者对象  
    command := &ConcreteCommand{receiver}   // 创建具体命令对象,并传入接收者对象作为参数  
    invoker := &Invoker{}   // 创建调用者对象  
    invoker.SetCommand(command)   // 将具体命令对象传递给调用者对象作为属性使用、回调或引用,从而实现请求者和具体命令对象的解耦。这样客户端代码只需要与调用者对象交互即可执行命令。
}

七、PHP命令模式

以下是一个示例,展示了如何在PHP中实现命令模式:

interface Command {  
    public function execute();  
    public function undo();  
}  
  
class ConcreteCommand implements Command {  
    private $receiver;  
      
    public function __construct(Receiver $receiver) {  
        $this->receiver = $receiver;  
    }  
      
    public function execute() {  
        $this->receiver->operation();  
    }  
      
    public function undo() {  
        $this->receiver->undo();  
    }  
}  
  
class Receiver {  
    public function operation() {  
        echo "Operation executed";  
    }  
      
    public function undo() {  
        echo "Operation undone";  
    }  
}  
  
class Invoker {  
    private $command;  
      
    public function setCommand(Command $command) {  
        $this->command = $command;  
    }  
      
    public function executeCommand() {  
        $this->command->execute();  
    }  
}

在客户端代码中,可以创建具体命令对象和调用者对象,并将它们组装起来。然后通过调用者对象来执行命令。例如:

$receiver = new Receiver();   // 创建接收者对象  
$command = new ConcreteCommand($receiver);   // 创建具体命令对象,并传入接收者对象作为参数  
$invoker = new Invoker();   // 创建调用者对象  
$invoker->setCommand($command);   // 将具体命令对象传递给调用者对象作为属性使用、回调或引用,从而实现请求者和具体命令对象的解耦。这样客户端代码只需要与调用者对象交互即可执行命令。


《完结》

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

postgresql14-模式的管理(三)

基本概念 postgresql成为数据库管理系统DBMS,在内存中以进程的形态运行起来成为一个实例,可管理多个database。 数据库databases:包含表、索引、视图、存储过程; 模式schema:多个对象组成一个模式,多个模…

09-React路由使用(React Router 6)

9-React Router 6的使用 1.概述 React Router 以三个不同的包发布到 npm 上,它们分别为: react-router: 路由的核心库,提供了很多的:组件、钩子。react-router-dom: 包含react-router所有内容,并添加一些专门用于 DOM …

期中考misc复现

第一题 flow analysis 1 服务器附带的后门文件名是什么?(包括文件后缀) webshell是网站的后门,也是一个命令解释器。不过是以http协议这样的方式通信。继承了web权限 我们过滤http和https http && http.response.code…

机器学习中常见的特征工程处理

一、特征工程 特征工程(Feature Engineering)对特征进行进一步分析,并对数据进行处理。 常见的特征工程包括:异常值处理、缺失值处理、数据分桶、特征处理、特征构造、特征筛选及降维等。 1、异常值处理 具体实现 from scipy.s…

ant javac任务的fork和executable属性

ant javac任务是用于编译源文件的。 它的fork属性表示是否用JDK编译器在外部执行javac,取值可以为"yes"、“no”,默认值为"no"。 当fork属性的取值为"yes"时,可以用executable属性指明javac可执行文件的完全…

clion本地调试nginx-1.22.1

1 概述 nginx是一个多进程模型的流量代理软件,在本地调试时需要将它设置为单进程模式。 2 下载nginx源码 mkdir -p /opt/third-party cd /opt/third-party wget http://nginx.org/download/nginx-1.22.1.tar.gz tar xf nginx-1.22.1.tar.gz ls /opt/third-party…

Linux系统自有服务

一、Linux中防火墙firewalld 1、什么是防火墙 防火墙:防范一些网络攻击。有软件防火墙、硬件防火墙之分。 防火墙选择让正常请求通过,从而保证网络安全性。 Windows防火墙: Windows防火墙的划分与开启、关闭操作: 2、防火墙的作…

程序员提高效率的工具和习惯分享

文档待完善.... 思维方式 X-Y Problem | 酷 壳 - CoolShell 程序员如何把控自己的职业 | 酷 壳 - CoolShell 笔记软件 语雀:多平台,云同步,md文档,在线协作; 一键启动必要的软件:bat脚本 电脑重启后可以…

canvas保存画笔的状态到栈里面

可以将画笔不同时刻的状态记录下来,然后保存到一个栈里面存储,后面可以在栈里面恢复画笔的状态,继续使用之前的状态绘制,效果如下:将红色,蓝色,黄色的状态都存储起来了,然后逐个恢复…

chatGPT结构及商业级相似模型应用调研

GPT前言 说明 ChatGPT这项技术的历史可以追溯到2018年,当时由Facebook实验室的团队开发出该技术,以开发聊天机器人为目的。随后,ChatGPT在2019年由来自谷歌的DeepMind团队在国际会议ICLR上发表了论文,其中提出了ChatGPT的技术框架…

怎么将PNG, JPEG, GIF,BMP等格式图片转化为ICO格式文件?

小ICO格式文件是一种包含一个或多个小尺寸图片的图片文件,主要应用在Windows系统中。 方法一:用软件进行格式转换 Quick Any2Ico 「【木头分享】Quick_Any2Ico.exe」:https://pan.quark.cn/s/ecda58bb2bd0 Quick Any2Ico是一款大小仅600K…

【逆向】Base64编码解码及逆向识别

示例代码 注意:该示例代码仅为Base64编码实现的其中一种,实际分析样本的Base64编码实现并不一定与此代码相同,读者应重点理解其原理部分,而忽略其实现形式的不同。 View Code 逆向识别 1、编码识别 2、解码识别 总结 1、识别代…

大模型与知识图谱如何相互助力

目前各行各业在数字化、智能化发展的大势所趋下,信息新技术不断涌现,也在加快深入融合到传统实体行业应用中,比如知识图谱、人工智能、数字孪生等等,特别是基于人工智能的大模型在去年底被chatgpt的带领下涌现出一波又一波的浪潮&…

阶段六-Day04-MyBatis2

一、别名 Alias 1. 为什么使用别名 一般映射文件中会包含大量<select>标签, 每个<select>中都需要配置resultType"com.bjsxt.pojo.People"&#xff0c;MyBatis提供了别名机制可以对某个类起别名或给某个包下所有类起别名&#xff0c;简化resultType取值…

面向对象【构造器】

文章目录 构造器定义构造器的作用构造器的使用说明无参构造器带参数的构造器构造器的重载使用构造器创建对象 总结 构造器定义 构造器是一种特殊类型的方法&#xff0c;它与类同名&#xff0c;没有返回值&#xff0c;并且用于在创建对象时执行初始化操作。构造器的名称必须与类…

C++笔记之关于函数名前的取址符

C笔记之关于函数名前的取址符 相关博文&#xff1a;C之指针探究(十一)&#xff1a;函数名的本质和函数指针 code review! 文章目录 C笔记之关于函数名前的取址符一.函数名可以被视为指向函数的地址二.sayHello和&sayHello是不是等同?三.Qt信号与槽中的取地址符& 一…

【Java】<泛型>,在编译阶段约束操作的数据结构,并进行检查。

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ JAVA泛型 泛型介绍&#xff1a; ①泛型&#…

julia笔记:函数

1 函数的定义&#xff08;两种方法&#xff09; function f(x,y)x yend #f (generic function with 1 method) f(x,y) x y #f(x,y) x y 2 匿名函数&#xff08;两种方法&#xff09; function (x,y)x yend ##3 (generic function with 1 method) (x,y)->x y ##5…

【2023年11月第四版教材】软考高项极限冲刺篇笔记(2)

1 我们要知道的事 1、考试的选择题不会出假大空的管理,一般较为具体 2.3 信息系统治理 首先治理的目标是什么 治理的管理层分为三层 原则:简单透明适合 COBIT IT审计范围:总体、组织、物理、逻辑、其他 IT审计风险:固有、控制、检查、总体审计 IT审计方法:访谈、调查、…

【Linux】进程间通信——共享内存

目录 一、什么是共享内存 二、共享内存的原理 三、使用共享内存实现进程间通信 3.1 shmget接口 3.1.1 key形参详解 3.2 释放共享内存 3.2.1 ipcs指令 3.2.2 ipcrm指令 3.2.3 shmctl接口 3.3 关联共享内存 3.4 去关联共享内存 3.5 使用共享内存进行进程间通信实例 …