经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » 设计模式 » 查看文章
【命令设计模式详解】C/Java/JS/Go/Python/TS不同语言实现
来源:cnblogs  作者:刀法如飞  时间:2023/3/31 8:58:48  对本文有异议

简介

命令模式(Command Pattern)是一种数据驱动的设计模式,也是一种行为型设计模式。这种模式的请求以命令的形式包裹在对象中,并传给调用对象。调用对象再寻找合适的对象,并把该命令传给相应的处理者。即把请求或操作封装成单个对象,并使其可以被参数化和延迟执行,这种方式将命令和执行者进行了有效解耦。

如果你需要通过操作来参数化对象,可使用命令模式。如果你想要将操作放入队列中、操作的执行或者远程执行操作, 可使用命令模式。如果你想要实现操作回滚功能,可使用命令模式。

作用

  1. 将不同命令按照抽象命令封装成不同的对象,将这些命令放到调用者里。
  2. 客户通过调用者执行命令再去调用接受者的动作,顺序为:客户调用方->调用者->命令对象->接受者。
  3. 同其他对象一样,命令也可以实现序列化,从而方便地写入文件或数据库中,实现延迟执行。

实现步骤

  1. 创建一个抽象命令接口,实现基本的命令方法。
  2. 创建多个具体命令类,实现抽象命令接口,以来命令接收者。
  3. 创建命令接收者,也就是具体业务类,接受命令并执行动作。
  4. 创建命令调用者,这是一个聚合命令的类,添加命令和执行命令。

UML

 

Java代码

基础命令接口

  1. // Command.java 命令抽象接口
  2. public interface Command {
  3. void execute();
  4. }

 

具体命令类,可以多个命令

  1. // BuyCommand.java 购买命令,操作receiver,实现了抽象命令类
  2. public class BuyCommand implements Command {
  3. private StockReceiver stockReceiver;
  4. public BuyCommand(StockReceiver stockReceiver) {
  5. this.stockReceiver = stockReceiver;
  6. }
  7. // 命令类调用执行者的实际动作
  8. public void execute() {
  9. System.out.println(this.getClass().getName() + "::execute() ");
  10. this.stockReceiver.buy();
  11. }
  12. }
  13. // SellCommand.java 出售命令,操作receiver,实现了抽象命令类
  14. public class SellCommand implements Command {
  15. private StockReceiver stockReceiver;
  16. public SellCommand(StockReceiver stockReceiver) {
  17. this.stockReceiver = stockReceiver;
  18. }
  19. // 命令类调用执行者的实际动作
  20. public void execute() {
  21. System.out.println(this.getClass().getName() + "::execute() ");
  22. stockReceiver.sell();
  23. }
  24. }

 

命令调用类

  1. // CommandInvoker.java 命令调用类,通过关联命令来执行命令的调用
  2. public class CommandInvoker {
  3. private List<Command> commandList = new ArrayList<Command>();
  4. // 储存命令
  5. public void takeOrder(Command command) {
  6. System.out.println(this.getClass().getName() + "::takeOrder() " + command.getClass().getName());
  7. commandList.add(command);
  8. }
  9. // 统一执行
  10. public void executeOrders() {
  11. System.out.println(this.getClass().getName() + "::executeOrders() ");
  12. for (Command command : commandList) {
  13. command.execute();
  14. }
  15. commandList.clear();
  16. }
  17. }

 

命令接收执行类

  1. // StockReceiver.java 命令模式真正的执行类,不直接对外,通过command来调用
  2. public class StockReceiver {
  3. private String name;
  4. private int num;
  5. public StockReceiver(String name, int num) {
  6. this.name = name;
  7. this.num = num;
  8. }
  9. public void buy() {
  10. System.out.println(this.getClass().getName() + "::buy() [name=" + this.name + " num=" + this.num + "]");
  11. }
  12. public void sell() {
  13. System.out.println(this.getClass().getName() + "::sell() [name=" + this.name + " num=" + this.num + "]");
  14. }
  15. public void setName(String name) {
  16. this.setName(name);
  17. }
  18. public String getName() {
  19. return this.name;
  20. }
  21. public void setNum(int num) {
  22. this.num = num;
  23. }
  24. public int getNum() {
  25. return this.num;
  26. }
  27. }

 

测试调用

  1. /*
  2. * 命令模式是客户端通过一个命令执行者invoker,去执行某个命令command。
  3. * 而命令则调用了业务类receiver的具体动作,从而完成真正的执行。
  4. * 这种方式将命令和执行者进行了有效解耦。
  5. */
  6.  
  7. // 先声明一个被操作对象,也就是接收者
  8. StockReceiver stock1 = new StockReceiver("Apple", 200);
  9. // 再声明具体的命令
  10. BuyCommand buyCommand = new BuyCommand(stock1);
  11. SellCommand sellCommand = new SellCommand(stock1);
  12. // 最后声明调用者,由调用者来执行具体命令
  13. CommandInvoker invoker = new CommandInvoker();
  14. invoker.takeOrder(buyCommand);
  15. invoker.takeOrder(sellCommand);
  16. invoker.executeOrders();
  17. // 再执行一只股票
  18. StockReceiver stock2 = new StockReceiver("Google", 100);
  19. BuyCommand buyCommand2 = new BuyCommand(stock2);
  20. invoker.takeOrder(buyCommand2);
  21. invoker.executeOrders();

 

Go代码

基础命令接口

  1. // Command.go 命令抽象接口
  2. type Command interface {
  3. GetName() string
  4. SetStockReceiver(stockReceiver *StockReceiver)
  5. Execute()
  6. }

 

具体命令类,可以多个命令

  1. // BuyCommand.go 购买命令,操作receiver,实现了抽象命令类
  2. type BuyCommand struct {
  3. Name string `default:"BuyCommand"`
  4. stockReceiver *StockReceiver
  5. }
  6. func (c *BuyCommand) GetName() string {
  7. return c.Name
  8. }
  9. func (c *BuyCommand) SetStockReceiver(stockReceiver *StockReceiver) {
  10. c.stockReceiver = stockReceiver
  11. }
  12. // 命令类调用执行者来自行真正的动作
  13. func (c *BuyCommand) Execute() {
  14. fmt.Println("BuyCommand::Execute() ")
  15. c.stockReceiver.Buy()
  16. }
  17. // SellCommand.go 出售命令,操作receiver,实现了抽象命令类
  18. type SellCommand struct {
  19. Name string `default:"BuyCommand"`
  20. stockReceiver *StockReceiver
  21. }
  22. func (s *SellCommand) GetName() string {
  23. return s.Name
  24. }
  25. func (s *SellCommand) SetStockReceiver(stockReceiver *StockReceiver) {
  26. s.stockReceiver = stockReceiver
  27. }
  28. // 命令类调用执行者来自行真正的动作
  29. func (s *SellCommand) Execute() {
  30. fmt.Println("SellCommand::Execute() ")
  31. s.stockReceiver.Sell()
  32. }

 

命令调用类

  1. // CommandInvoker.go 命令调用类,通过关联命令来执行命令的调用
  2. type CommandInvoker struct {
  3. Name string
  4. commandList []Command
  5. }
  6. func (c *CommandInvoker) GetName() string {
  7. return c.Name
  8. }
  9. // 储存命令
  10. func (c *CommandInvoker) TakeOrder(command Command) {
  11. fmt.Println("CommandInvoker::TakeOrder() " + command.GetName())
  12. c.commandList = append(c.commandList, command)
  13. }
  14. // 统一执行
  15. func (c *CommandInvoker) ExecuteOrders() {
  16. fmt.Println("CommandInvoker::ExecuteOrders() ")
  17. for _, command := range c.commandList {
  18. command.Execute()
  19. }
  20. // 命令执行后清除
  21. c.commandList = c.commandList[:0]
  22. }

 

命令接收执行类

  1. // StockReceiver.go 命令模式真正的执行类,不直接对外,通过command来调用
  2. type StockReceiver struct {
  3. Name string
  4. Num int
  5. }
  6. func (s *StockReceiver) Buy() {
  7. fmt.Println("StockReceiver::Buy() [Name=" +
  8. s.Name + " Num=" + strconv.Itoa(s.Num) + "]")
  9. }
  10. func (s *StockReceiver) Sell() {
  11. fmt.Println("StockReceiver::Sell() [Name=" +
  12. s.Name + " Num=" + strconv.Itoa(s.Num) + "]")
  13. }

 

测试调用

  1. // main包下的main入口方法
  2. func main() {
  3. fmt.Println("test start:")
  4. /*
  5. * 命令模式是客户端通过一个命令执行者invoker,去执行某个命令command
  6. * 而命令则调用了业务类receiver的具体动作,从而完成真正的执行
  7. * 这种方式将命令和执行者进行了有效解耦。
  8. */
  9.  
  10. // 先声明一个被操作对象,也就是接收者
  11. var stock1 = &src.StockReceiver{
  12. Name: "Apple",
  13. Num: 200,
  14. }
  15. // 再声明具体的命令
  16. var buyCommand = &src.BuyCommand{
  17. Name: "buyCommand",
  18. }
  19. buyCommand.SetStockReceiver(stock1)
  20. var sellCommand = &src.SellCommand{
  21. Name: "sellCommand",
  22. }
  23. sellCommand.SetStockReceiver(stock1)
  24. // 最后声明调用者,由调用者来执行具体命令
  25. var invoker = &src.CommandInvoker{
  26. Name: "invoker",
  27. }
  28. invoker.TakeOrder(buyCommand)
  29. invoker.TakeOrder(sellCommand)
  30. invoker.ExecuteOrders()
  31. // 再执行一只股票
  32. var stock2 = &src.StockReceiver{
  33. Name: "Google",
  34. Num: 100,
  35. }
  36. var buyCommand2 = &src.BuyCommand{
  37. Name: "buyCommand2",
  38. }
  39. buyCommand2.SetStockReceiver(stock2)
  40. invoker.TakeOrder(buyCommand2)
  41. invoker.ExecuteOrders()
  42. }

 

C语言代码

基础对象定义

  1. // func.h文件,基础命令结构体head
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <stdbool.h>
  5. #include <string.h>
  6.  
  7. // 基础命令结构体
  8. typedef struct Command
  9. {
  10. char name[50];
  11. struct StockReceiver *stock_receiver;
  12. void (*set_stock_receiver)(struct Command *command, struct StockReceiver *);
  13. void (*execute)(struct Command *);
  14. } Command;
  15. // 接受者对象
  16. typedef struct StockReceiver
  17. {
  18. char name[50];
  19. int num;
  20. void (*buy)(struct StockReceiver *);
  21. void (*sell)(struct StockReceiver *);
  22. } StockReceiver;
  23. StockReceiver *stock_receiver_constructor(char *name, int num);
  24. // 继承命令结构体
  25. typedef struct BuyCommand
  26. {
  27. char name[50];
  28. struct StockReceiver *stock_receiver;
  29. void (*set_stock_receiver)(struct BuyCommand *command, struct StockReceiver *);
  30. void (*execute)(struct Command *);
  31. } BuyCommand;
  32. BuyCommand *buy_command_constructor(char *name);
  33. // 继承命令结构体
  34. typedef struct SellCommand
  35. {
  36. char name[50];
  37. struct StockReceiver *stock_receiver;
  38. void (*set_stock_receiver)(struct SellCommand *command, struct StockReceiver *);
  39. void (*execute)(struct Command *);
  40. } SellCommand;
  41. SellCommand *sell_command_constructor(char *name);
  42. // 命令执行者
  43. typedef struct CommandInvoker
  44. {
  45. char name[50];
  46. void (*take_order)(struct CommandInvoker *invoker, Command *command);
  47. void (*execute_orders)(struct CommandInvoker *invoker);
  48. // 数组命令列表,记录待执行的命令对象
  49. struct Command **command_list;
  50. // 数组长度记录
  51. int command_list_size;
  52. // 若是柔性数组,则放在结构体最后,可以动态追加内容
  53. // struct Command *command_list[];
  54. } CommandInvoker;
  55. CommandInvoker *command_invoker_constructor(char *name);

 

具体命令类,可以多个命令

  1. // buy_command.c 购买命令,操作receiver,实现了抽象命令类
  2. #include "func.h"
  3.  
  4. // 购买命令,操作receiver,实现了抽象命令类
  5.  
  6. void set_buy_stock_receiver(BuyCommand *command, StockReceiver *receiver)
  7. {
  8. command->stock_receiver = receiver;
  9. }
  10. // 命令类调用执行者来自行真正的动作
  11. void buy_command_execute(Command *command)
  12. {
  13. printf("\r\n BuyCommand::execute() [command->name=%s]", command->name);
  14. command->stock_receiver->buy(command->stock_receiver);
  15. }
  16. // 创建Buy命令对象
  17. BuyCommand *buy_command_constructor(char *name)
  18. {
  19. Command *command = (Command *)malloc(sizeof(Command));
  20. strncpy(command->name, name, 50);
  21. command->execute = &buy_command_execute;
  22. // 转为BuyCommand
  23. BuyCommand *buy_command = (BuyCommand *)command;
  24. buy_command->set_stock_receiver = &set_buy_stock_receiver;
  25. return buy_command;
  26. }
  27. // sell_command.c 出售命令,操作receiver,实现了抽象命令类
  28. #include "func.h"
  29.  
  30. // 出售命令,操作receiver,实现了抽象命令类
  31.  
  32. void set_sell_stock_receiver(SellCommand *command, StockReceiver *receiver) {
  33. command->stock_receiver = receiver;
  34. }
  35. // 命令类调用执行者来自行真正的动作
  36. void sell_command_execute(Command *command) {
  37. printf("\r\n SellCommand::execute() [command->name=%s]", command->name);
  38. command->stock_receiver->sell(command->stock_receiver);
  39. }
  40. // 创建Sell命令对象
  41. SellCommand *sell_command_constructor(char *name)
  42. {
  43. Command *command = (Command *)malloc(sizeof(Command));
  44. strncpy(command->name, name, 50);
  45. command->execute = &sell_command_execute;
  46. // 转为SellCommand
  47. SellCommand *buy_command = (SellCommand *)command;
  48. buy_command->set_stock_receiver = &set_sell_stock_receiver;
  49. return buy_command;
  50. }

 

命令调用类

  1. // command_invoker.c 命令调用类,通过关联命令来执行命令的调用
  2. #include "func.h"
  3.  
  4. /*
  5. 命令调用类,通过关联命令来实行命令的调用
  6. 在命令模式中,Invoker(调用者)是一个可选的组件,
  7. 它负责将Command对象传递给Receiver,
  8. 并调用Command对象的execute方法来执行命令。
  9. Invoker在实现命令模式时可以有多种实现方式。
  10. */
  11.  
  12. void print_command_list(Command **list, int command_list_size)
  13. {
  14. printf("\r\nThe current command_list:");
  15. for (int i = 0; i < command_list_size; i++)
  16. {
  17. printf("\r\n [i=%d, command->name=%s]", i, list[i]->name);
  18. }
  19. }
  20. // 把命令存储到调用者的命令列表
  21. void invoker_take_order(CommandInvoker *invoker, Command *command)
  22. {
  23. printf("\r\n CommandInvoker::take_order() [invoker->name=%s, command->name=%s, invoker->command_list_size=%d]", invoker->name, command->name, invoker->command_list_size);
  24. // 列表长度增加1位
  25. int new_command_list_size = invoker->command_list_size + 1;
  26. /* 如果采取柔性数组,则无需申请新空间和复制内容 */
  27. // 把原列表命令暂存下来
  28. Command **old_command_list = invoker->command_list;
  29. // 给命令列表申请新空间
  30. invoker->command_list = (Command **)calloc(new_command_list_size, sizeof(Command *));
  31. // 复制原有命令到命令列表,如果采取柔性数组则无需复制
  32. for (int i = 0; i < invoker->command_list_size; i++)
  33. {
  34. invoker->command_list[i] = old_command_list[i];
  35. }
  36. free(old_command_list);
  37. // 把新的命令添加列表最后
  38. invoker->command_list[new_command_list_size - 1] = command;
  39. invoker->command_list_size = new_command_list_size;
  40. // 打印当前有多少命令
  41. // print_command_list(invoker->command_list, invoker->command_list_size);
  42. }
  43. // 统一执行全部命令
  44. void invoker_execute_orders(CommandInvoker *invoker)
  45. {
  46. printf("\r\n CommandInvoker::execute_orders() ");
  47. int command_list_size = invoker->command_list_size;
  48. Command **command_list = invoker->command_list;
  49. for (int i = 0; i < command_list_size; i++)
  50. {
  51. Command *command = command_list[i];
  52. command->execute(command);
  53. command_list[i] = NULL;
  54. }
  55. // 命令执行完后清除命令列表
  56. invoker->command_list_size = 0;
  57. invoker->command_list = (Command **)calloc(0, sizeof(Command *));
  58. }
  59. // 初始化CommandInvoker命令对象
  60. CommandInvoker *command_invoker_constructor(char *name)
  61. {
  62. printf("\r\n command_invoker_constructor() [name=%s]", name);
  63. CommandInvoker *invoker = (CommandInvoker *)malloc(sizeof(CommandInvoker));
  64. strncpy(invoker->name, name, 50);
  65. invoker->command_list_size = 0;
  66. invoker->take_order = &invoker_take_order;
  67. invoker->execute_orders = &invoker_execute_orders;
  68. return invoker;
  69. }

 

命令接收执行类

  1. // stock_receiver.c 命令模式真正的执行类,不直接对外,通过command来调用
  2. #include "func.h"
  3.  
  4. /* 命令模式真正的执行类,不直接对外,通过command来调用 */
  5.  
  6. void stock_receiver_buy(StockReceiver *stock_receiver) {
  7. printf("\r\n StockReceiver::buy() [name=%s num=%d]", stock_receiver->name, stock_receiver->num);
  8. }
  9. void stock_receiver_sell(StockReceiver *stock_receiver) {
  10. printf("\r\n StockReceiver::sell() [name=%s num=%d]", stock_receiver->name, stock_receiver->num);
  11. }
  12. // 创建StockReceiver命令对象
  13. StockReceiver *stock_receiver_constructor(char *name, int num)
  14. {
  15. printf("\r\n stock_receiver_constructor() [name=%s, num=%d]", name, num);
  16. StockReceiver *receiver = (StockReceiver *)malloc(sizeof(StockReceiver));
  17. strncpy(receiver->name, name, 50);
  18. receiver->num = num;
  19. receiver->buy = &stock_receiver_buy;
  20. receiver->sell = &stock_receiver_sell;
  21. return receiver;
  22. }

 

测试调用

  1. #include "../src/func.h"
  2.  
  3. int main(void)
  4. {
  5. printf("test start:\r\n");
  6. /*
  7. * 命令模式是一种行为设计模式,它将请求或操作封装成单个对象,并使其可以被参数化和延迟执行。
  8. * 在命令模式中,客户端通过一个命令执行者invoker,去执行某个命令command
  9. * 而命令则调用了业务类receiver的具体动作,从而完成真正的执行
  10. * 这种方式将命令和执行者进行了有效解耦。
  11. */
  12.  
  13. // 先声明一个被操作对象,也就是接收者
  14. StockReceiver *stocker_receiver1 = stock_receiver_constructor("Apple", 200);
  15. // 再声明具体的命令
  16. BuyCommand *buy_command = buy_command_constructor("buy_command");
  17. buy_command->set_stock_receiver(buy_command, stocker_receiver1);
  18. SellCommand *sell_command = sell_command_constructor("sell_command");
  19. sell_command->set_stock_receiver(sell_command, stocker_receiver1);
  20. // 最后声明调用者,由调用者来执行具体命令
  21. CommandInvoker *invoker = command_invoker_constructor("invoker");
  22. invoker->take_order(invoker, (Command *)buy_command);
  23. invoker->take_order(invoker, (Command *)sell_command);
  24. invoker->execute_orders(invoker);
  25. // 再执行一只股票,声明新的接受者
  26. StockReceiver *stock_receiver2 = stock_receiver_constructor("Google", 100);
  27. BuyCommand *buy_command2 = buy_command_constructor("buy_command2");
  28. // 这次只有buy命令
  29. buy_command2->set_stock_receiver(buy_command2, stock_receiver2);
  30. // 还用原来的invoker,或者新建invoker
  31. invoker->take_order(invoker, (Command *)buy_command2);
  32. invoker->execute_orders(invoker);
  33. return 0;
  34. }

 

更多语言版本

不同语言实现设计模式源码:https://github.com/microwind/design-pattern

原文链接:https://www.cnblogs.com/letjs/p/17273541.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号