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

概述:命令模式 ∈ 行为型模式

模式定义

  • 命令模式Command Pattern)是一种数据驱动的设计模式
  • 属于行为型模式
  • 命令模式将一个请求封装为一个对象,从而使你可以用不同的请求对客户进行参数化,对请求排队记录请求日志,以及支持可撤销的操作

  • 主要解决的问题

解决在软件系统请求者执行者之间的紧耦合问题,特别是在需要对行为进行记录撤销/重做事务处理等场景。

模式的组成

  • 【命令】(Command):

定义了执行操作的接口,通常包含一个 execute 方法,用于调用具体的操作。

  • 具体命令(ConcreteCommand):

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

  • 【接收者】(Receiver):

知道如何执行与请求相关的操作,实际执行命令的对象。

  • 【调用者/请求者】(Invoker):

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

  • 客户端(Client):

创建具体命令对象,并设置其接收者,将命令对象交给调用者执行。

实现方式

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

模式特点

优点

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

缺点

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

使用建议

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

适用场景

  • 使用时机:当需要先将一个函数【登记】上,然后再以后【调用】此函数时,就需要使用命令模式

有时候需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是什么。
此时希望用一种松耦合的方式来设计程序,使得请求发送者请求接收者能够消除彼此之间的耦合关系

  • 例子:拿订餐来说,客人需要向厨师发送请求,但是完全不知道这些厨师的名字和联系方式,也不知道厨师炒菜的方式和步骤。

命令模式把客人订餐的请求封装成 command 对象,也就是订餐中的订单对象
这个对象可以在程序中被四处传递,就像订单可以从服务员手中传到厨师的手中。
这样一来,客人不需要知道厨师的名字,从而解开了请求调用者请求接收者之间的耦合关系

案例实践

CASE 命令模式的实现

Receiver

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

Command

  • Command类 : 用来声明执行操作的接口
abstract class Command {
    protected Receiver receiver;
    public Command(Receiver receiver) {
        this.receiver = receiver;
    }
    abstract public void Execute();
}

ConcreteCommand

  • ConcreteCommand类,将一个接受者对象绑定于一个动作,调用接受者相应的操作,以实现Execute。
class ConcreteCommand : Command {
    public ConcreteCommand(Receiver receiver) : base(receiver) {
    }

    public override void Execute() {
        receiver.Action();
    }
}

Invoker

  • Invoker类: 要求该命令执行这个请求
class Invoker {
    private Command command;
    public void SetCommand(Command command) {
        this.command = command;
    }

    public void ExecuteCommand() {
        command.Execute();
    }
}

Client

static void Main(string[] args) {
    Receiver r = new Receiver();//接收者,如:厨师
    Command c = new ConcreteCommand(r);//创建具体命令,如:点菜(麻婆豆腐)

    Invoker i = new Invoker();//调用者,如:客户小美
    i.SetCommand(c);//设置具体命令
    i.ExecuteCommand();//执行命令

    Console.Read();
}

CASE 股票订单的买入、卖出

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

Order : 命令接口

public interface Order {
   void execute();
}

Stock : 请求类

public class Stock {
   private String name = "ABC";
   private int quantity = 100;
 
   public void buy(){
      System.out.println("Stock [ Name: "+name+", 
         Quantity: " + quantity +" ] bought");
   }
   public void sell(){
      System.out.println("Stock [ Name: "+name+", 
         Quantity: " + quantity +" ] sold");
   }
}

BuyStock / SellStock : 具体的请求类

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

  • BuyStock 买入股票
public class BuyStock implements Order {
   private Stock abcStock;
 
   public BuyStock(Stock abcStock){
      this.abcStock = abcStock;
   }
 
   public void execute() {
      abcStock.buy();
   }
}
  • SellStock 售出股票
public class SellStock implements Order {
   private Stock abcStock;
 
   public SellStock(Stock abcStock){
      this.abcStock = abcStock;
   }
 
   public void execute() {
      abcStock.sell();
   }
}

Broker : 命令调用类

创建命令调用类。

import java.util.ArrayList;
import java.util.List;
 
public class Broker {
   private List<Order> orderList = new ArrayList<Order>(); //订单列表
 
   public void takeOrder(Order order){//接收订单
      orderList.add(order);      
   }
 
   public void placeOrders(){//下订单
      for (Order order : orderList) {
         order.execute();
      }
      orderList.clear();
   }
}

Client

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

  • CommandPatternDemo
public class CommandPatternDemo {
   public static void main(String[] args) {
      Stock abcStock = new Stock();
 
      BuyStock buyStockOrder = new BuyStock(abcStock);
      SellStock sellStockOrder = new SellStock(abcStock);
 
      Broker broker = new Broker();
      broker.takeOrder(buyStockOrder);
      broker.takeOrder(sellStockOrder);
 
      broker.placeOrders();
   }
}

out

Stock [ Name: ABC, Quantity: 100 ] bought
Stock [ Name: ABC, Quantity: 100 ] sold

Y 推荐文献

X 参考文献

posted @ 2025-04-26 22:03  千千寰宇  阅读(78)  评论(0)    收藏  举报