设计模式:命令模式(Command Pattern)及实例

news/2025/1/21 9:27:29/文章来源:https://www.cnblogs.com/FatTiger4399/p/18238059

 好家伙,

 

0.什么是命令模式

在软件系统中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。

但在某些场合,比如要对行为进行“记录、撤销/重做、事务”等处理,这种无法抵御变化的紧耦合是不合适的。

在这种情况下,如何将“行为请求者”与“行为实现者”解耦?将一组行为抽象为对象实现二者之间的松耦合。这就是命令模式(Command Pattern)。

 

 0.1.角色解释

Command(定义接口): 定义命令的接口,声明执行的方法。

ConcreteCommand(实现接口):命令接口实现对象,是“虚”的实现;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。

Receiver(接收者):接收者,真正执行命令的对象。任何类都可能成为一个接收者,只要它能够实现命令要求实现的相应功能。

Invoker(调用者):要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。

    这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。

Client(具体命令):创建具体的命令对象,并且设置命令对象的接收者。注意这个不是我们常规意义上的客户端,而是在组装命令对象和接收者,或许,

    把这个Client称为装配者会更好理解,因为真正使用命令的客户端是从Invoker来触发执行

 

0.2.模式分析

1.命令模式的本质是对命令进行封装,将发出命令的责任和执行命令的责任分割开
2.每一个命令都是一个操作:请求的一方发出请求,要求执行一个操作;接收的一方收到请求,并执行操作
3.命令模式允许请求的一方和接收的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收,以及操作是否被执行、何时被执行,以及是怎么被执行的。
4.命令模式使请求本身成为一个对象,这个对象和其他对象一样可以被存储和传递。
5.命令模式的关键在于引入了抽象命令接口,且发送者针对抽象命令接口编程,只有实现了抽象命令接口的具体命令才能与接收者相关联
 

0.3.模式优点

1.降低对象之间的耦合度。
2.新的命令可以很容易地加入到系统中。
3.可以比较容易地设计一个组合命令。
4.调用同一方法实现不同的功能
 

0.4.缺点

使用命令模式可能会导致某些系统有过多的具体命令类。因为针对每一个命令都需要设计一个具体命令类,因此某些系统可能需要大量具体命令类,这将影响命令模式的使用。
 
                                                          ----以上内容均来自“百度百科”
 

 

1.实例

想象一个实例

餐厅点餐案例

现在我走进一家餐厅,向一名服务员点餐,点了一份牛肉汉堡,

服务员将这份”牛肉汉堡"订单交给厨师,厨师制作这份牛肉牛肉汉堡

来个代码实现

// 厨师类
class Chef {makeBurger() {console.log("This is your burger.");}
}// 服务员类
class Waitress {constructor(chef) {this.chef = chef;}takeOrder(order) {// 服务员接收订单并处理console.log("Waitress is taking the order for a " + order);this.chef.makeBurger(); // 直接通知厨师制作汉堡
  }
}// 客户端代码
(() => {const chef = new Chef();const waitress = new Waitress(chef);// 客户点餐 服务员通知waitress.takeOrder("burger");
})();

 

那么如果我使用命令模式去实现呢?

// 命令接口(抽象概念,使用ES6的类来表示)
class Command {execute() {// 抽象方法execute,将在具体命令中实现throw new Error('You should implement the execute method');}
}// 具体命令类
class OrderBurgerCommand extends Command {constructor(receiver) {super();this.receiver = receiver;}execute() {this.receiver.makeBurger();}
}// 接收者类
class Chef {makeBurger() {console.log("Chef is making a burger.");}
}// 请求者类
class Waitress {constructor() {this.commands = [];}takeOrder(command) {if (!(command instanceof Command)) {throw new Error('You can only take order of Command instances');}this.commands.push(command);}notify() {this.commands.forEach(command => command.execute());}
}// 客户类
class Customer {constructor() {this.waitress = new Waitress();this.chef = new Chef();this.burgerCommand = new OrderBurgerCommand(this.chef);}orderBurger() {this.waitress.takeOrder(this.burgerCommand);}serveOrder() {this.waitress.notify();}
}// 客户端代码
(() => {const customer = new Customer();customer.orderBurger();  // 客户点餐customer.serveOrder();   // 服务员通知厨师制作汉堡
})();

 

 

2.增加需求

同样的,如果我们新下单一条“薯条”

使用命令模式

// 命令模式实现// 命令接口
class Command {execute() {// 抽象方法,需要在子类中实现
    }
}// 汉堡命令
class BurgerCommand extends Command {constructor(chef) {super();this.chef = chef;}execute() {this.chef.makeBurger();}
}// 薯条命令
class FrenchFriesCommand extends Command {constructor(chef) {super();this.chef = chef;}execute() {this.chef.makeFrenchFries();}
}// 厨师类
class Chef {makeBurger() {console.log('制作汉堡');}makeFrenchFries() {console.log('制作薯条');}
}// 服务员类
class Waiter {constructor() {this.commands = [];}order(command) {this.commands.push(command);console.log('订单已接收');}serve() {this.commands.forEach(command => command.execute());}
}// 客户类
class Customer {constructor(waiter) {this.waiter = waiter;}orderBurger() {const chef = new Chef();const burgerCommand = new BurgerCommand(chef);this.waiter.order(burgerCommand);}orderFrenchFries() {const chef = new Chef();const friesCommand = new FrenchFriesCommand(chef);this.waiter.order(friesCommand);}
}// 客户端代码
(() => {const waiter = new Waiter();const customer = new Customer(waiter);// 客户点一份汉堡
    customer.orderBurger();// 客户再点一份薯条
    customer.orderFrenchFries();// 服务员开始服务
    waiter.serve();
})();

再结合以上代码来看,命令模式的优势有

1.真正实现了解耦:客户不需要知道汉堡制作的细节,服务员也不需要知道汉堡制作的细节,客户仅仅是下单,服务员仅仅是通知

2.易于扩展:如果需要添加新的操作(如包装、加热),可以创建新的命令类,而无需修改现有的类结构。

 

通过汉堡和薯条的例子,我们可以看到命令模式如何使得代码更加灵活、可维护,并且更容易进行扩展。

 

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

gRPC入门学习之旅(十)

gRPC是一个高性能、通用的开源远程过程调用(RPC)框架,基于底层HTTP/2协议标准和协议层Protobuf序列化协议开发, gRPC 客户端和服务端可以在多种环境中运行和交互。你可以用Java创建一个 gRPC 服务端,用 Go、Python、C# 来创建客户端。本系统文章详细描述了如何创建一个自己…

WPS使用技巧|word

分享 WPS word文档的编辑技巧代码 代码高亮 推荐工具:https://highlightcode.com 我们把需要插入的代码复制上去,再点击右上角的 高亮代码把代码复制到WPS即可 效果演示:本文将持续更新……

面向对象程序设计-第4-6次大作业总结

前言 有了三次大作业的经验,即使在面对新的大作业时谈不上得心应手,但也有了一些思路以及应对难点的方法,总归是有了一些心得体会,不会被复杂的测试点和样例搞得捉襟见肘,这也未尝不算进步。 1.知识点 这三次大作业的知识点相较于前几次来说更加复杂,更加专业化,涉及到了…

2024年5月文章一览

2024年5月编程人总共更新了7篇文章: 1.2024年4月文章一览 2.《自动机理论、语言和计算导论》阅读笔记:p215-p351 3.《自动机理论、语言和计算导论》阅读笔记:p352-P401 4.《自动机理论、语言和计算导论》阅读笔记:p402-p427 5.《自动机理论、语言和计算导论》阅读笔记:p42…

BUUCTF-WEB(66-70)

[MRCTF2020]套娃 参考: MRCTF2020 套娃 - Rabbittt - 博客园 (cnblogs.com) upfine的博客 (cnblogs.com) 查看源码然后我这里查一下$_SERVER的这个用法然后这边的意思就是里面不能用_和%5f(URL编码过的下划线) 然后传入b_u_p_t里面这个参数有下划线,我们想办法绕过 substr_cou…

告别Word,用Python打造你的专业简历!

今天给大家介绍下一个在纯 python 中构建简历的实用工具,工具的连接地址https://github.com/koek67/resume-builder/blob/main/readme.md 用法介绍 要求 Python 3.7 或更高版本(仅此而已!) 安装 整个库是一个单独的 python 文件 resume_builder.py。下载此文件 用法 要生成…

某大型医院IBM 3650服务器 raid重组案例——数据完美修复

我们今天谈的是一个来自四川的大型三甲医院的服务器数据恢复的真实的一个案例,是一台IBM的3650服务器,一共六块硬盘坏了,有两块硬盘是300GB,一共是有六块盘,两块盘是曝光灯离线了,导致这个医院的挂号系统,诊疗系统全部瘫痪,所有数据全部丢失,医院属于一个停摆的状态,…

数据库镜像 (SQL Server)操作模式

数据库镜像会话以同步操作或异步操作运行。 在异步操作下,事务不需要等待镜像服务器将日志写入磁盘便可提交,这样可最大程度地提高性能。 在同步操作下,事务将在伙伴双方处提交,但会延长事务滞后时间。 有两种镜像运行模式。 一种是高安全性模式,它支持同步操作。 在高安全…

Block Transformer:通过全局到局部的语言建模加速LLM推理

在基于transformer的自回归语言模型(LMs)中,生成令牌的成本很高,这是因为自注意力机制需要关注所有之前的令牌,通常通过在自回归解码过程中缓存所有令牌的键值(KV)状态来解决这个问题。但是,加载所有先前令牌的KV状态以计算自注意力分数则占据了LMs的推理的大部分成本。…

Android Media Framework(四)Non-Tunneled组件的状态转换与buffer分配过程分析

本篇将继续深入OpenMAX IL Spec,详细解析Non-tunneled(非隧道)组件的初始化、数据传递以及组件销毁过程。通过阅读本篇内容,我们应能对Non-tunneled组件的buffer分配与状态转换过程有一个清晰的了解。1、组件初始化 以下是IL Spec给的Non-tunneled组件初始化时序图:IL Cli…

庆余年第二季迅雷下载/庆余年2全集下载百度云在线观看

《庆余年2》:承前启后的豪情与智慧近年来,电视剧《庆余年》以其精彩的剧情和精湛的演技,收获了广大观众的喜爱和好评。而续集作品《庆余年2》更是在原剧的基础上迈出了更加坚实的一步。该剧不仅延续了第一季的精彩故事,同时也在新一季中增加了更多的情节和角色,带给观众更…