概述:命令模式 ∈ 行为型模式
模式定义
- 命令模式(Command Pattern)是一种数据驱动的设计模式
- 命令模式将一个请求封装为一个对象,从而使你可以用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。
- 主要解决的问题
解决在软件系统中请求者和执行者之间的紧耦合问题,特别是在需要对行为进行记录、撤销/重做或事务处理等场景。
模式的组成
定义了执行操作的接口,通常包含一个 execute 方法,用于调用具体的操作。
实现了命令接口,负责执行具体的操作。
它通常包含了对接收者的引用,通过调用接收者的execute方法来完成请求的处理。
知道如何执行与请求相关的操作,实际执行命令的对象。
发送命令的对象,它包含了一个命令对象并能触发命令的执行。
调用者并不直接处理请求,而是通过将请求传递给命令对象来实现。
创建具体命令对象,并设置其接收者,将命令对象交给调用者执行。
实现方式
- 定义命令接口:所有命令必须实现的接口。
- 创建具体命令:实现命令接口的具体类,包含执行请求的方法。
- 调用者:持有命令对象并触发命令的执行。
- 接收者:实际执行命令的对象。
模式特点
优点
- 降低耦合度:请求者和执行者之间的耦合度降低。
- 易于扩展:新命令可以很容易地添加到系统中。
缺点
- 过多命令类:系统可能会有过多的具体命令类,增加系统的复杂度。
使用建议
- 如果系统需要支持命令的撤销(Undo)和恢复(Redo)操作,命令模式也是一个合适的选择。
- 在GUI中,每个按钮或菜单项可以视为一条命令。
- 在需要模拟命令行操作的场景中使用命令模式。
适用场景
- 使用时机:当需要先将一个函数【登记】上,然后再以后【调用】此函数时,就需要使用命令模式
有时候需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是什么。
此时希望用一种松耦合的方式来设计程序,使得请求发送者和请求接收者能够消除彼此之间的耦合关系。
- 例子:拿订餐来说,客人需要向厨师发送请求,但是完全不知道这些厨师的名字和联系方式,也不知道厨师炒菜的方式和步骤。
命令模式把客人订餐的请求封装成 command 对象,也就是订餐中的订单对象。
这个对象可以在程序中被四处传递,就像订单可以从服务员手中传到厨师的手中。
这样一来,客人不需要知道厨师的名字,从而解开了请求调用者和请求接收者之间的耦合关系
案例实践
CASE 命令模式的实现
Receiver
- Receiver类 : 知道如何实施与执行一个与请求相关的操作,任何类都可能作为一个接受者
- public class Receiver {
- public void Action() {
- Console.WriteLine("执行请求!");
- }
- }
复制代码 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
- 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 类。
- 实体命令类 BuyStock 和 SellStock,实现了 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 接口的实体类。
- public class BuyStock implements Order {
- private Stock abcStock;
-
- public BuyStock(Stock abcStock){
- this.abcStock = abcStock;
- }
-
- public void execute() {
- abcStock.buy();
- }
- }
复制代码- 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 类来接受并执行命令
- 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 参考文献
- 命令模式 - 菜鸟教程
- 深入理解设计模式(十):命令模式 - 博客园 【推荐】
本文作者: 千千寰宇
本文链接: https://www.cnblogs.com/johnnyzen
关于博文:评论和私信会在第一时间回复,或直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
日常交流:大数据与软件开发-QQ交流群: 774386015 【入群二维码】参见左下角。您的支持、鼓励是博主技术写作的重要动力!
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |