找回密码
 立即注册
首页 业界区 业界 【命令设计模式详解】C/Java/JS/Go/Python/TS不同语言实 ...

【命令设计模式详解】C/Java/JS/Go/Python/TS不同语言实现

诸婉丽 2025-6-6 09:36:59
简介

命令模式(Command Pattern)是一种数据驱动的设计模式,也是一种行为型设计模式。这种模式的请求以命令的形式包裹在对象中,并传给调用对象。调用对象再寻找合适的对象,并把该命令传给相应的处理者。即把请求或操作封装成单个对象,并使其可以被参数化和延迟执行,这种方式将命令和执行者进行了有效解耦。
如果你需要通过操作来参数化对象,可使用命令模式。如果你想要将操作放入队列中、操作的执行或者远程执行操作, 可使用命令模式。如果你想要实现操作回滚功能,可使用命令模式。
作用


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


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

1.png


 
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.     StockReceiver stock1 = new StockReceiver("Apple", 200);
  8.     // 再声明具体的命令
  9.     BuyCommand buyCommand = new BuyCommand(stock1);
  10.     SellCommand sellCommand = new SellCommand(stock1);
  11.     // 最后声明调用者,由调用者来执行具体命令
  12.     CommandInvoker invoker = new CommandInvoker();
  13.     invoker.takeOrder(buyCommand);
  14.     invoker.takeOrder(sellCommand);
  15.     invoker.executeOrders();
  16.     // 再执行一只股票
  17.     StockReceiver stock2 = new StockReceiver("Google", 100);
  18.     BuyCommand buyCommand2 = new BuyCommand(stock2);
  19.     invoker.takeOrder(buyCommand2);
  20.     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.   var stock1 = &src.StockReceiver{
  11.     Name: "Apple",
  12.     Num:  200,
  13.   }
  14.   // 再声明具体的命令
  15.   var buyCommand = &src.BuyCommand{
  16.     Name: "buyCommand",
  17.   }
  18.   buyCommand.SetStockReceiver(stock1)
  19.   var sellCommand = &src.SellCommand{
  20.     Name: "sellCommand",
  21.   }
  22.   sellCommand.SetStockReceiver(stock1)
  23.   // 最后声明调用者,由调用者来执行具体命令
  24.   var invoker = &src.CommandInvoker{
  25.     Name: "invoker",
  26.   }
  27.   invoker.TakeOrder(buyCommand)
  28.   invoker.TakeOrder(sellCommand)
  29.   invoker.ExecuteOrders()
  30.   // 再执行一只股票
  31.   var stock2 = &src.StockReceiver{
  32.     Name: "Google",
  33.     Num:  100,
  34.   }
  35.   var buyCommand2 = &src.BuyCommand{
  36.     Name: "buyCommand2",
  37.   }
  38.   buyCommand2.SetStockReceiver(stock2)
  39.   invoker.TakeOrder(buyCommand2)
  40.   invoker.ExecuteOrders()
  41. }
复制代码
 
C语言代码

基础对象定义
  1. // func.h文件,基础命令结构体head
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <stdbool.h>
  5. #include <string.h>
  6. // 基础命令结构体
  7. typedef struct Command
  8. {
  9.     char name[50];
  10.     struct StockReceiver *stock_receiver;
  11.     void (*set_stock_receiver)(struct Command *command, struct StockReceiver *);
  12.     void (*execute)(struct Command *);
  13. } Command;
  14. // 接受者对象
  15. typedef struct StockReceiver
  16. {
  17.     char name[50];
  18.     int num;
  19.     void (*buy)(struct StockReceiver *);
  20.     void (*sell)(struct StockReceiver *);
  21. } StockReceiver;
  22. StockReceiver *stock_receiver_constructor(char *name, int num);
  23. // 继承命令结构体
  24. typedef struct BuyCommand
  25. {
  26.     char name[50];
  27.     struct StockReceiver *stock_receiver;
  28.     void (*set_stock_receiver)(struct BuyCommand *command, struct StockReceiver *);
  29.     void (*execute)(struct Command *);
  30. } BuyCommand;
  31. BuyCommand *buy_command_constructor(char *name);
  32. // 继承命令结构体
  33. typedef struct SellCommand
  34. {
  35.     char name[50];
  36.     struct StockReceiver *stock_receiver;
  37.     void (*set_stock_receiver)(struct SellCommand *command, struct StockReceiver *);
  38.     void (*execute)(struct Command *);
  39. } SellCommand;
  40. SellCommand *sell_command_constructor(char *name);
  41. // 命令执行者
  42. typedef struct CommandInvoker
  43. {
  44.     char name[50];
  45.     void (*take_order)(struct CommandInvoker *invoker, Command *command);
  46.     void (*execute_orders)(struct CommandInvoker *invoker);
  47.     // 数组命令列表,记录待执行的命令对象
  48.     struct Command **command_list;
  49.     // 数组长度记录
  50.     int command_list_size;
  51.     // 若是柔性数组,则放在结构体最后,可以动态追加内容
  52.     // struct Command *command_list[];
  53. } CommandInvoker;
  54. CommandInvoker *command_invoker_constructor(char *name);
复制代码
 
具体命令类,可以多个命令
  1. // buy_command.c 购买命令,操作receiver,实现了抽象命令类
  2. #include "func.h"
  3. // 购买命令,操作receiver,实现了抽象命令类
  4. void set_buy_stock_receiver(BuyCommand *command, StockReceiver *receiver)
  5. {
  6.   command->stock_receiver = receiver;
  7. }
  8. // 命令类调用执行者来自行真正的动作
  9. void buy_command_execute(Command *command)
  10. {
  11.   printf("\r\n BuyCommand::execute() [command->name=%s]", command->name);
  12.   command->stock_receiver->buy(command->stock_receiver);
  13. }
  14. // 创建Buy命令对象
  15. BuyCommand *buy_command_constructor(char *name)
  16. {
  17.   Command *command = (Command *)malloc(sizeof(Command));
  18.   strncpy(command->name, name, 50);
  19.   command->execute = &buy_command_execute;
  20.   // 转为BuyCommand
  21.   BuyCommand *buy_command = (BuyCommand *)command;
  22.   buy_command->set_stock_receiver = &set_buy_stock_receiver;
  23.   return buy_command;
  24. }
  25. // sell_command.c 出售命令,操作receiver,实现了抽象命令类
  26. #include "func.h"
  27. // 出售命令,操作receiver,实现了抽象命令类
  28. void set_sell_stock_receiver(SellCommand *command, StockReceiver *receiver) {
  29.   command->stock_receiver = receiver;
  30. }
  31. // 命令类调用执行者来自行真正的动作
  32. void sell_command_execute(Command *command) {
  33.   printf("\r\n SellCommand::execute() [command->name=%s]", command->name);
  34.   command->stock_receiver->sell(command->stock_receiver);
  35. }
  36. // 创建Sell命令对象
  37. SellCommand *sell_command_constructor(char *name)
  38. {
  39.   Command *command = (Command *)malloc(sizeof(Command));
  40.   strncpy(command->name, name, 50);
  41.   command->execute = &sell_command_execute;
  42.   // 转为SellCommand
  43.   SellCommand *buy_command = (SellCommand *)command;
  44.   buy_command->set_stock_receiver = &set_sell_stock_receiver;
  45.   return buy_command;
  46. }
复制代码
 
命令调用类
  1. // command_invoker.c 命令调用类,通过关联命令来执行命令的调用
  2. #include "func.h"
  3. /*
  4. 命令调用类,通过关联命令来实行命令的调用
  5. 在命令模式中,Invoker(调用者)是一个可选的组件,
  6. 它负责将Command对象传递给Receiver,
  7. 并调用Command对象的execute方法来执行命令。
  8. Invoker在实现命令模式时可以有多种实现方式。
  9. */
  10. void print_command_list(Command **list, int command_list_size)
  11. {
  12.   printf("\r\nThe current command_list:");
  13.   for (int i = 0; i < command_list_size; i++)
  14.   {
  15.     printf("\r\n [i=%d, command->name=%s]", i, list[i]->name);
  16.   }
  17. }
  18. // 把命令存储到调用者的命令列表
  19. void invoker_take_order(CommandInvoker *invoker, Command *command)
  20. {
  21.   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);
  22.   // 列表长度增加1位
  23.   int new_command_list_size = invoker->command_list_size + 1;
  24.   /* 如果采取柔性数组,则无需申请新空间和复制内容 */
  25.   // 把原列表命令暂存下来
  26.   Command **old_command_list = invoker->command_list;
  27.   // 给命令列表申请新空间
  28.   invoker->command_list = (Command **)calloc(new_command_list_size, sizeof(Command *));
  29.   // 复制原有命令到命令列表,如果采取柔性数组则无需复制
  30.   for (int i = 0; i < invoker->command_list_size; i++)
  31.   {
  32.     invoker->command_list[i] = old_command_list[i];
  33.   }
  34.   free(old_command_list);
  35.   // 把新的命令添加列表最后
  36.   invoker->command_list[new_command_list_size - 1] = command;
  37.   invoker->command_list_size = new_command_list_size;
  38.   
  39.   // 打印当前有多少命令
  40.   // print_command_list(invoker->command_list, invoker->command_list_size);
  41. }
  42. // 统一执行全部命令
  43. void invoker_execute_orders(CommandInvoker *invoker)
  44. {
  45.   printf("\r\n CommandInvoker::execute_orders() ");
  46.   int command_list_size = invoker->command_list_size;
  47.   Command **command_list = invoker->command_list;
  48.   for (int i = 0; i < command_list_size; i++)
  49.   {
  50.     Command *command = command_list[i];
  51.     command->execute(command);
  52.     command_list[i] = NULL;
  53.   }
  54.   // 命令执行完后清除命令列表
  55.   invoker->command_list_size = 0;
  56.   invoker->command_list = (Command **)calloc(0, sizeof(Command *));
  57. }
  58. // 初始化CommandInvoker命令对象
  59. CommandInvoker *command_invoker_constructor(char *name)
  60. {
  61.   printf("\r\n command_invoker_constructor() [name=%s]", name);
  62.   CommandInvoker *invoker = (CommandInvoker *)malloc(sizeof(CommandInvoker));
  63.   strncpy(invoker->name, name, 50);
  64.   invoker->command_list_size = 0;
  65.   invoker->take_order = &invoker_take_order;
  66.   invoker->execute_orders = &invoker_execute_orders;
  67.   return invoker;
  68. }
复制代码
 
命令接收执行类
  1. // stock_receiver.c 命令模式真正的执行类,不直接对外,通过command来调用
  2. #include "func.h"
  3. /* 命令模式真正的执行类,不直接对外,通过command来调用 */
  4. void stock_receiver_buy(StockReceiver *stock_receiver) {
  5.   printf("\r\n StockReceiver::buy() [name=%s num=%d]", stock_receiver->name, stock_receiver->num);
  6. }
  7. void stock_receiver_sell(StockReceiver *stock_receiver) {
  8.   printf("\r\n StockReceiver::sell() [name=%s num=%d]", stock_receiver->name, stock_receiver->num);
  9. }
  10. // 创建StockReceiver命令对象
  11. StockReceiver *stock_receiver_constructor(char *name, int num)
  12. {
  13.   printf("\r\n stock_receiver_constructor() [name=%s, num=%d]", name, num);
  14.   StockReceiver *receiver = (StockReceiver *)malloc(sizeof(StockReceiver));
  15.   strncpy(receiver->name, name, 50);
  16.   receiver->num = num;
  17.   receiver->buy = &stock_receiver_buy;
  18.   receiver->sell = &stock_receiver_sell;
  19.   return receiver;
  20. }
复制代码
 
测试调用
  1. #include "../src/func.h"
  2. int main(void)
  3. {
  4.     printf("test start:\r\n");
  5.     /*
  6.      * 命令模式是一种行为设计模式,它将请求或操作封装成单个对象,并使其可以被参数化和延迟执行。
  7.      * 在命令模式中,客户端通过一个命令执行者invoker,去执行某个命令command
  8.      * 而命令则调用了业务类receiver的具体动作,从而完成真正的执行
  9.      * 这种方式将命令和执行者进行了有效解耦。
  10.      */
  11.     // 先声明一个被操作对象,也就是接收者
  12.     StockReceiver *stocker_receiver1 = stock_receiver_constructor("Apple", 200);
  13.     // 再声明具体的命令
  14.     BuyCommand *buy_command = buy_command_constructor("buy_command");
  15.     buy_command->set_stock_receiver(buy_command, stocker_receiver1);
  16.     SellCommand *sell_command = sell_command_constructor("sell_command");
  17.     sell_command->set_stock_receiver(sell_command, stocker_receiver1);
  18.     // 最后声明调用者,由调用者来执行具体命令
  19.     CommandInvoker *invoker = command_invoker_constructor("invoker");
  20.     invoker->take_order(invoker, (Command *)buy_command);
  21.     invoker->take_order(invoker, (Command *)sell_command);
  22.     invoker->execute_orders(invoker);
  23.     // 再执行一只股票,声明新的接受者
  24.     StockReceiver *stock_receiver2 = stock_receiver_constructor("Google", 100);
  25.     BuyCommand *buy_command2 = buy_command_constructor("buy_command2");
  26.     // 这次只有buy命令
  27.     buy_command2->set_stock_receiver(buy_command2, stock_receiver2);
  28.     // 还用原来的invoker,或者新建invoker
  29.     invoker->take_order(invoker, (Command *)buy_command2);
  30.     invoker->execute_orders(invoker);
  31.     return 0;
  32. }
复制代码
 
更多语言版本

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

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册