找回密码
 立即注册
首页 业界区 安全 [设计模式/Java] 设计模式之命令模式【26】 ...

[设计模式/Java] 设计模式之命令模式【26】

骆贵 2025-5-31 23:53:47
概述:命令模式 ∈ 行为型模式

模式定义


  • 命令模式(Command Pattern)是一种数据驱动的设计模式


  • 属于行为型模式


  • 命令模式将一个请求封装为一个对象,从而使你可以用不同的请求对客户进行参数化,对请求排队记录请求日志,以及支持可撤销的操作
  • 主要解决的问题
解决在软件系统请求者执行者之间的紧耦合问题,特别是在需要对行为进行记录撤销/重做事务处理等场景。
模式的组成

1.png


  • 【命令】(Command):
定义了执行操作的接口,通常包含一个 execute 方法,用于调用具体的操作。


  • 具体命令(ConcreteCommand):
实现了命令接口,负责执行具体的操作
它通常包含了对接收者的引用,通过调用接收者的execute方法来完成请求的处理。


  • 【接收者】(Receiver):
知道如何执行与请求相关的操作,实际执行命令的对象。


  • 【调用者/请求者】(Invoker):
发送命令的对象,它包含了一个命令对象并能触发命令的执行。
调用者并不直接处理请求,而是通过将请求传递给命令对象来实现。


  • 客户端(Client):
创建具体命令对象,并设置其接收者,将命令对象交给调用者执行。
2.png

实现方式


  • 定义命令接口:所有命令必须实现的接口。
  • 创建具体命令:实现命令接口的具体类,包含执行请求的方法。
  • 调用者:持有命令对象并触发命令的执行。
  • 接收者:实际执行命令的对象。
模式特点

优点


  • 降低耦合度请求者执行者之间的耦合度降低。
  • 易于扩展:新命令可以很容易地添加到系统中。
缺点


  • 过多命令类:系统可能会有过多的具体命令类,增加系统的复杂度。
使用建议


  • 如果系统需要支持命令撤销(Undo)和恢复(Redo)操作,命令模式也是一个合适的选择。
  • 在GUI中,每个按钮菜单项可以视为一条命令
  • 在需要模拟命令行操作的场景中使用命令模式
适用场景


  • 使用时机:当需要先将一个函数【登记】上,然后再以后【调用】此函数时,就需要使用命令模式
有时候需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是什么。
此时希望用一种松耦合的方式来设计程序,使得请求发送者请求接收者能够消除彼此之间的耦合关系


  • 例子:拿订餐来说,客人需要向厨师发送请求,但是完全不知道这些厨师的名字和联系方式,也不知道厨师炒菜的方式和步骤。
命令模式把客人订餐的请求封装成 command 对象,也就是订餐中的订单对象
这个对象可以在程序中被四处传递,就像订单可以从服务员手中传到厨师的手中。
这样一来,客人不需要知道厨师的名字,从而解开了请求调用者请求接收者之间的耦合关系
案例实践

CASE 命令模式的实现

Receiver


  • Receiver类 : 知道如何实施与执行一个与请求相关的操作,任何类都可能作为一个接受者
  1. public class Receiver {
  2.     public void Action() {
  3.         Console.WriteLine("执行请求!");
  4.     }
  5. }
复制代码
Command


  • Command类 : 用来声明执行操作的接口
  1. abstract class Command {
  2.     protected Receiver receiver;
  3.     public Command(Receiver receiver) {
  4.         this.receiver = receiver;
  5.     }
  6.     abstract public void Execute();
  7. }
复制代码
ConcreteCommand


  • ConcreteCommand类,将一个接受者对象绑定于一个动作,调用接受者相应的操作,以实现Execute。
  1. class ConcreteCommand : Command {
  2.     public ConcreteCommand(Receiver receiver) : base(receiver) {
  3.     }
  4.     public override void Execute() {
  5.         receiver.Action();
  6.     }
  7. }
复制代码
Invoker


  • Invoker类: 要求该命令执行这个请求
  1. class Invoker {
  2.     private Command command;
  3.     public void SetCommand(Command command) {
  4.         this.command = command;
  5.     }
  6.     public void ExecuteCommand() {
  7.         command.Execute();
  8.     }
  9. }
复制代码
Client
  1. static void Main(string[] args) {
  2.     Receiver r = new Receiver();//接收者,如:厨师
  3.     Command c = new ConcreteCommand(r);//创建具体命令,如:点菜(麻婆豆腐)
  4.     Invoker i = new Invoker();//调用者,如:客户小美
  5.     i.SetCommand(c);//设置具体命令
  6.     i.ExecuteCommand();//执行命令
  7.     Console.Read();
  8. }
复制代码
CASE 股票订单的买入、卖出


  • 我们首先创建作为命令的接口 Order,然后创建作为请求的 Stock 类。
  • 实体命令类 BuyStock 和 SellStock,实现了 Order 接口,将执行实际的命令处理。
  • 创建作为调用对象的类 Broker,它接受订单并能下订单。
  • Broker 对象使用命令模式,基于命令的类型确定哪个对象执行哪个命令。
  • CommandPatternDemo 类使用 Broker 类来演示命令模式。
3.png

Order : 命令接口
  1. public interface Order {
  2.    void execute();
  3. }
复制代码
Stock : 请求类
  1. public class Stock {
  2.    private String name = "ABC";
  3.    private int quantity = 100;
  4.    public void buy(){
  5.       System.out.println("Stock [ Name: "+name+",
  6.          Quantity: " + quantity +" ] bought");
  7.    }
  8.    public void sell(){
  9.       System.out.println("Stock [ Name: "+name+",
  10.          Quantity: " + quantity +" ] sold");
  11.    }
  12. }
复制代码
BuyStock / SellStock : 具体的请求类

创建实现了 Order 接口的实体类。


  • BuyStock 买入股票
  1. public class BuyStock implements Order {
  2.    private Stock abcStock;
  3.    public BuyStock(Stock abcStock){
  4.       this.abcStock = abcStock;
  5.    }
  6.    public void execute() {
  7.       abcStock.buy();
  8.    }
  9. }
复制代码

  • SellStock 售出股票
  1. public class SellStock implements Order {
  2.    private Stock abcStock;
  3.    public SellStock(Stock abcStock){
  4.       this.abcStock = abcStock;
  5.    }
  6.    public void execute() {
  7.       abcStock.sell();
  8.    }
  9. }
复制代码
Broker : 命令调用类

创建命令调用类。
  1. import java.util.ArrayList;
  2. import java.util.List;
  3. public class Broker {
  4.    private List<Order> orderList = new ArrayList<Order>(); //订单列表
  5.    public void takeOrder(Order order){//接收订单
  6.       orderList.add(order);      
  7.    }
  8.    public void placeOrders(){//下订单
  9.       for (Order order : orderList) {
  10.          order.execute();
  11.       }
  12.       orderList.clear();
  13.    }
  14. }
复制代码
Client

使用 Broker 类来接受并执行命令


  • CommandPatternDemo
  1. public class CommandPatternDemo {
  2.    public static void main(String[] args) {
  3.       Stock abcStock = new Stock();
  4.       BuyStock buyStockOrder = new BuyStock(abcStock);
  5.       SellStock sellStockOrder = new SellStock(abcStock);
  6.       Broker broker = new Broker();
  7.       broker.takeOrder(buyStockOrder);
  8.       broker.takeOrder(sellStockOrder);
  9.       broker.placeOrders();
  10.    }
  11. }
复制代码
out
  1. Stock [ Name: ABC, Quantity: 100 ] bought
  2. Stock [ Name: ABC, Quantity: 100 ] sold
复制代码
Y 推荐文献


  • 设计模式之总述 - 博客园/千千寰宇
X 参考文献


  • 命令模式 - 菜鸟教程
  • 深入理解设计模式(十):命令模式 - 博客园 【推荐】
    本文作者:        千千寰宇   
    本文链接:         https://www.cnblogs.com/johnnyzen   
    关于博文:评论和私信会在第一时间回复,或直接私信我。   
    版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA     许可协议。转载请注明出处!
    日常交流:大数据与软件开发-QQ交流群: 774386015        【入群二维码】参见左下角。您的支持、鼓励是博主技术写作的重要动力!   

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