好家伙,

 

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

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

设计模式:命令模式(Command Pattern)及实例的更多相关文章

  1. 设计模式 - 命令模式(command pattern) 多命令 具体解释

    命令模式(command pattern) 多命令 具体解释 本文地址: http://blog.csdn.net/caroline_wendy 參考命令模式: http://blog.csdn.ne ...

  2. 设计模式 - 命令模式(command pattern) 具体解释

    命令模式(command pattern) 详细解释 本文地址: http://blog.csdn.net/caroline_wendy 命令模式(command pattern) : 将请求封装成对 ...

  3. 设计模式 - 命令模式(command pattern) 宏命令(macro command) 具体解释

    命令模式(command pattern) 宏命令(macro command) 具体解释 本文地址: http://blog.csdn.net/caroline_wendy 參考: 命名模式(撤销) ...

  4. 设计模式 - 命令模式(command pattern) 撤销(undo) 具体解释

    命令模式(command pattern) 撤销(undo) 详细解释 本文地址: http://blog.csdn.net/caroline_wendy 參考命令模式: http://blog.cs ...

  5. 大话设计模式--命令模式 Command -- C++实现实例

    1. 命令模式: 将请求封装为一个对象,从而使你可以用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作. 命令模式有点: a. 较容易的设计一个命令队列 b. 在需要的的情况 ...

  6. C#设计模式——命令模式(Command Pattern)

    一.概述通常来说,“行为请求者”与“行为实现者”是紧耦合的.但在某些场合,比如要对行为进行“记录.撤销/重做.事务”等处理,这种无法抵御变化的紧耦合是不合适的.在这些情况下,将“行为请求者”与“行为实 ...

  7. 乐在其中设计模式(C#) - 命令模式(Command Pattern)

    原文:乐在其中设计模式(C#) - 命令模式(Command Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 命令模式(Command Pattern) 作者:webabcd ...

  8. 二十四种设计模式:命令模式(Command Pattern)

    命令模式(Command Pattern) 介绍将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化:对请求排队或记录请求日志,以及支持可取消的操作. 示例有一个Message实体类,某个 ...

  9. 设计模式-15命令模式(Command Pattern)

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

  10. 设计模式(六):控制台中的“命令模式”(Command Pattern)

    今天的博客中就来系统的整理一下“命令模式”.说到命令模式,我就想起了控制台(Console)中的命令.无论是Windows操作系统(cmd.exe)还是Linux操作系统(命令行式shell(Comm ...

随机推荐

  1. 宜搭5月更新:跨应用数据读写能力升级,AI组件内测开放

    ​简介:表单.权限管理.AI组件等功能上新啦- 本次,我们带来了表单.权限管理.数据管理.平台管理权限.组件等功能的升级. 表单 支持跨应用数据查询 在使用组件数据联动.关联其他表单数据.关联表单组件 ...

  2. CNCF 沙箱项目 OCM Placement 多集群调度指南

    ​简介:在这篇文章中,将介绍 Placement 如何选择到所需的集群,Placement 可以提供的调度功能,以及一些场景下的最佳实践,使用者可以参考示例来编写符合自己要求的 Placement.其 ...

  3. [FAQ] 设置 npm 镜像源

    查看 npm 源: $ npm config get registry> http://registry.npmjs.org/ 修改 npm 源: $ npm config set regist ...

  4. ESP32 分区表

    当你编译程序,发现 app partition is too small for binary 错误的时候,就涉及到 ESP32 分区表的内容了. 一.基本概念 在了解分区之前,先了解一下以下概率,便 ...

  5. 从零开始:Django项目的创建与配置指南

    title: 从零开始:Django项目的创建与配置指南 date: 2024/5/2 18:29:33 updated: 2024/5/2 18:29:33 categories: 后端开发 tag ...

  6. SuperSonic简介

    SuperSonic融合ChatBI和HeadlessBI打造新一代的数据分析平台.通过SuperSonic的问答对话界面,用户能够使用自然语言查询数据,系统会选择合适的可视化图表呈现结果. Supe ...

  7. redo日志全部丢失的情况下。Oracle的实例恢复

    场景: redo日志全部丢失的场景. alert日志报错如下: ORA-00313: 无法打开日志组 1 (用于线程 1) 的成员 ORA-00312: 联机日志 1 线程 1: '/u01/app/ ...

  8. gorm 返回的 *DB 说明

    RecordNotFound 跟在查询的后面(Find/First),bool true:没有查到记录 false:查到记录 Error 跟在修改(create/update)的后面,如果错误就会报错 ...

  9. JS实现下拉框切换和tab标签切换

    现在商城网页上会有下拉框切换内容,是如何实现的呢,研究了一天,在调整js代码和查找bug.最终完成了自己想要的效果,我没有写CSS样式,只是实现了基本功能,如果对你有所帮助,可以自己写css,使其更加 ...

  10. Docker打包程序镜像

    简介 做了一个视频检测程序,它是由golang和c++编写的.因为公司要做私有化部署,因此需要打包成镜像然后放到公司的registry镜像仓库里.之前一直没有去熟悉docker,现在刚好机会来了,咱就 ...