C# -- 设计模式 -- Command Pattern 命令模式

记录《Head First 设计模式》
参考 Graphic Design Patterns网站深入设计模式
目的是检查学习情况,同时方便以后复习。



一、简述

1-1 意图

命令模式 CommandPattern:
  Encapsulate a request as an Object .
  Allows the Parameterization of Clients with different requests.
  Allows Saving the request in a queue.
  Proving an object-oriented callbact.

将请求封装成对象,从而使用不同的请求对客户进行参数化、对请求排队(队列)或记录请求日志。命令模式也可以支持撤销操作。又称为动作模式或事务模式。该模式是一种 行为型模式

1-2 动机

使请求调用者与接收者完全解耦,请求调用者与接收者没有直接引用关系,发送请求的对象只需知道如何发送请求,无法知道如何完成请求。这就是命令模式的动机。

1-3 模式结构

  • Client:客户
  • Invoker:调用者
  • Command:命令接口
  • ConcreteCommand:具体命令者
  • Receiver:接收者
    模式结构

1-4 时序图

Client Receiver ConcreteCommand Invoker 1. new Receiver() 2. new ConcreteCommand() 3. new Invoker() 4. SetCommand() 5. Execute() 6. Action() 7. return result 8. return result 9. return result Client Receiver ConcreteCommand Invoker

二、代码示例:

1-1 封装请求

设计一款家电自动化遥控器,其中包括客厅灯开关、电视开关(开包含声音大小默认为7)、所有灯开关、空调开关(开包含温度为24、开启冷风热风)、吊扇开(高中低)关等。下面以灯为具体命令者举例。

命令接口:

 /// <summary>
 /// 命令模式:将“请求”封装成对象
 /// </summary>
 public interface Command
 {
     /// <summary>
     /// 执行请求
     /// </summary>
     public void Execute();
 }

具体命令者----灯开操作

/// <summary>
/// 具体命令者:灯开操作
/// </summary>
public class LightOnCommand : Command
{
    /// <summary>
    /// 对象
    /// </summary>
    Light Light;

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="light"></param>
    public LightOnCommand(Light light)
    {
        Light = light;
    }
    /// <summary>
    /// 执行请求
    /// </summary>
    public void Execute()
    {
        // 接收者执行相关请求
        Light.on();
    }
}

接收者----灯

/// <summary>
/// 接受者:执行命令相关操作
/// </summary>
public class Light
{
    /// <summary>
    /// 开灯
    /// </summary>
    public void on()
    {
        Console.WriteLine("Light is ON");
    }
    /// <summary>
    /// 关灯
    /// </summary>
    public void off()
    {
        Console.WriteLine("Light is OFF");
    }
}

调用者----简单控制

/// <summary>
/// 调用者
/// </summary>
public class SimpleRemoteControl
{
    /// <summary>
    /// 命令接口:存储命令者
    /// </summary>
    Command _command;
    public SimpleRemoteControl() { }

    /// <summary>
    /// 命令对象存储在调用者中
    /// </summary>
    /// <param name="command"></param>
    public void SetCommand(Command command)
    {
        _command = command;
    }
    /// <summary>
    /// 调用命令模式的执行请求方法
    /// </summary>
    public void ButtonWasPressed()
    {
        _command.Execute();
    }
}

执行命令模式

public class Program
{
    public static void Main(string[] arg)
    {
        // 调用者
        SimpleRemoteControl control = new SimpleRemoteControl();
        // 接收者
        Light light = new Light();
        // 具体命令者
        Command LightCommand = new LightOnCommand(light);
        // 向调用者传递命令者
        control.SetCommand(LightCommand);
        // 调用命令接口执行请求
        control.ButtonWasPressed();
    }
}

执行结果
执行结果

1-2 撤销

命令模式支持撤销操作,下面让我们在遥控器上加上撤销功能。
功能使用举例:客厅灯初始状态为关状态,当你按下遥控器《开》操作,灯会打开。按下《撤销》按钮,那就就会回到执行《开》操作之前。下面让我们看一下如果执行撤销操作。

具体命令类----灯开操作

/// <summary>
/// 具体命令者:灯开操作
/// </summary>
public class LightOnCommand : Command
{
    /// <summary>
    /// 对象
    /// </summary>
    Light Light;

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="light"></param>
    public LightOnCommand(Light light)
    {
        Light = light;
    }
    /// <summary>
    /// 执行请求
    /// </summary>
    public void Execute()
    {
        //接受者执行相关请求
        Light.on();
    }
    /// <summary>
    /// 撤销功能
    /// </summary>
    public void Undo()
    {
        Light.off();
    }
}

具体命令类----灯关操作

/// <summary>
/// 具体命令类 -灯关操作
/// </summary>
public class LightOffCommand : Command
{
    /// <summary>
    /// 对象
    /// </summary>
    Light Light;

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="light"></param>
    public LightOffCommand(Light light)
    {
        Light = light;
    }
    /// <summary>
    /// 执行请求
    /// </summary>
    public void Execute()
    {
        //接受者执行相关请求
        Light.off();
    }
    /// <summary>
    /// 撤销功能
    /// </summary>
    public void Undo()
    {
        Light.on();
    }
}

调用者----遥控器

/// <summary>
/// 调用者-遥控器 
/// </summary>
public class RemoteControlWithUndo
{
    Command[] onCommands;
    Command[] offCommands;
    Command undoCommand;

    public RemoteControlWithUndo()
    {
        onCommands = new Command[7] ;
        offCommands = new Command[7] ;

        Command noCommand = new NoCommand();
        for (int i = 0; i < 7; i++)
        {
            onCommands[i] = noCommand;
            offCommands[i] = noCommand;
        }
        undoCommand = noCommand;
    }
    /// <summary>
    /// 遥控按钮
    /// </summary>
    /// <param name="solt"></param>
    /// <param name="onCommand"></param>
    /// <param name="offCommand"></param>
    public void SetCommand(int solt, Command onCommand = null, Command offCommand = null)
    {
        onCommands[solt] = onCommand;
        offCommands[solt] = offCommand;
    }
    /// <summary>
    /// 某个按钮开
    /// </summary>
    /// <param name="slot"></param>
    public void onButtonWasPushed(int slot)
    {
        onCommands[slot].Execute();
        undoCommand = onCommands[slot];
    }
    /// <summary>
    /// 某个按钮关
    /// </summary>
    /// <param name="slot"></param>
    public void offButtonWasPushed(int slot)
    {
        offCommands[slot].Execute();
        undoCommand = offCommands[slot];
    }
    /// <summary>
    /// 撤销
    /// </summary>
    /// <param name="slot"></param>
    public void undoButtonWasPushed(int slot)
    {
        Console.WriteLine("撤销");
        undoCommand.Undo();
    }
}

具体命令类----初始默认

/// <summary>
/// 没有命令:初始状态
/// </summary>
public class NoCommand : Command
{
    public void Execute()
    {
        Console.WriteLine("默认状态");
    }

    public void Undo()
    {
        Console.WriteLine("无撤销");
    }
}

执行命令模式

public class Program
{
    public static void Main(string[] arg)
    {
        // 调用者
        RemoteControlWithUndo control = new RemoteControlWithUndo();
        // 接收者
        Light light = new Light();
        // 具体命令者
        Command LightOnCommand = new LightOnCommand(light);
        Command LightOffCommand = new LightOffCommand(light);
        // 向调用者传递命令者
        control.SetCommand(0, LightOnCommand, LightOffCommand);
        
        // 调用命令接口执行请求
        control.onButtonWasPushed(0);
        // 撤销
        control.undoButtonWasPushed(0);


        Console.WriteLine();
        Console.WriteLine();

        // 调用命令接口执行请求
        control.offButtonWasPushed(0);
        // 撤销
        control.undoButtonWasPushed(0);
    }
}

执行结果
执行结果

三、总结

1-1 模式分析

命令模式的本质是对命令进行封装,将发出命令的责任与执行命令的责任分隔开。

  • 每一个命令都是一个操作:请求的一方发布请求,要求执行一个操作;接收的一方收到请求,并执行操作。
  • 命令模式允许请求的一方与接收请求的一方独立开,使得请求的一方不必知道接收请求一方的接口,更不比知道请求是如何被接收,以及操作是否被执行、何时执行,以及怎么被执行。
  • 命令模式使请求本身成为一个对象,这个对象和其他对象一样可以被存储和传递。
  • 命令模式的关键在于引入了抽象命令接口,且发送者针对命令接口编程,只有实现抽象命令接口的具体命令才能与接收者相关联。

1-2 模式优缺点

优点:

  • 单一职责原理。可以解耦调用者与接收者。
  • 开闭原则。在不修改已有客户端代码的情况下在程序中创建新的命令。
  • 可以实现撤销和恢复功能。
  • 可以实现操作的延迟执行。
  • 可以比较容易地设计一个命令列或宏命令(组命令)

缺点:

  • 代码变得更加复杂,因为在调用者与接收者之间增加了一个全新的层次。
  • 使用命令模式可能会导致某些系统有过多的具体命令类(针对请求接收者的每一个调用都需要设计一个具体命令类)。

1-3 适合场景

适用场景:

  • 系统中需要将调用者与接收者进行解耦,使调用者与接收者之间不交互。
  • 请求者需要在不同的时间指定请求、将请求排队和执行请求。
  • 系统需要撤销(Undo)和 恢复(Redo)操作。
  • 系统需要将一组操作组合在一起,即支持宏命令。
  • 日志请求:所有动作记录在日志中,并在系统死机后。重新调用这些动作恢复到之前的状态。

1-4 模式应用

模式应用:

  • 系统提供宏命令功能,例如:UNIX平台下的Shell编程,可以将多条命令封装在一个命令对象中,只需要一条简单的命令即可执行一个命令序列
  • 队列请求:日志安排(Scheduler)、线程池、工作队列等。

1-5 总结

  • 命令模式将发出请求的对象(调用者)与执行请求的对象(接收者)解耦
  • 在被解耦的两者之间是通过命令模式进行沟通。命令对象封装了接收者和一个或一组动作。
  • 命令模式的本质是对命令进行封装,将发出命令的责任和执行命令的责任分隔开。命令模式使请求本身成为一个对象,这个对象和其他对象一样可以被存储和传递。
  • 宏命令是命令的一种简单的延伸,允许调用多个命令,同样宏命令也支持撤销操作。
  • 实际操作时,很常见使用“聪明”命令对象,也就是直接实现了请求,而不是将工作委托给接收者。
  • 命令也可以实现日志和事务系统。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
创建型: 1. 单件模式(Singleton Pattern) 2. 抽象工厂(Abstract Factory) 3. 建造者模式(Builder) 4. 工厂方法模式(Factory Method) 5. 原型模式(Prototype) 结构型: 6. 适配器模式(Adapter Pattern) 7. 桥接模式(Bridge Pattern) 8. 装饰模式(Decorator Pattern) 9. 组合模式(Composite Pattern) 10. 外观模式(Facade Pattern) 11. 享元模式(Flyweight Pattern) 12. 代理模式(Proxy Pattern) 13. 模板方法(Template Method) 14. 命令模式(Command Pattern) 15. 迭代器模式(Iterator Pattern) 行为型: 16. 观察者模式(Observer Pattern) 17. 解释器模式(Interpreter Pattern) 18. 中介者模式(Mediator Pattern) 19. 职责链模式(Chain of Responsibility Pattern) 20. 备忘录模式(Memento Pattern) 21. 策略模式(Strategy Pattern) 22. 访问者模式(Visitor Pattern) 23. 状态模式(State Pattern) 工程结构 ├─01.Singleton │ ├─html │ └─MySingleton │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ └─TempPE │ └─Properties ├─02.ChainOfResponsibility │ ├─html │ ├─My2ChainOfResponsibility │ │ ├─bin │ │ │ └─Debug │ │ ├─obj │ │ │ └─Debug │ │ │ └─TempPE │ │ └─Properties │ └─MyChainOfResponsibility │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ ├─Refactor │ │ └─TempPE │ └─Properties ├─03.FactoryMethodMode │ ├─FactoryMethodMode │ │ ├─bin │ │ │ └─Debug │ │ ├─obj │ │ │ └─Debug │ │ │ └─TempPE │ │ └─Properties │ └─html ├─04.AbstractFactory │ ├─04.1.SimpleFactory │ │ ├─html │ │ └─SimpleFactory │ │ ├─bin │ │ │ └─Debug │ │ ├─obj │ │ │ └─Debug │ │ │ └─TempPE │ │ └─Properties │ ├─AbstractFactory │ │ ├─bin │ │ │ └─Debug │ │ ├─obj │ │ │ └─Debug │ │ │ └─TempPE │ │ └─Properties │ └─html ├─05.BuilderPattern │ ├─html │ └─MyBuilderPattern │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ └─TempPE │ └─Properties ├─06.PrototypePattern │ ├─html │ │ └─C#设计模式(6)——原型模式(Prototype Patt O技术博客_files │ └─PrototypePattern │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ └─TempPE │ └─Properties ├─07.AdapterPattern │ ├─html │ └─MyAdapterPattern │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ └─TempPE │ └─Properties ├─08.BridgePattern │ ├─html │ └─MyBridgePattern │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ └─TempPE │ └─Properties ├─09.DecoratorPattern │ ├─html │ └─MyDecoratorPattern │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ └─TempPE │ └─Properties ├─10.CompositePattern │ ├─html │ └─MyCompositePattern │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ └─TempPE │ └─Properties ├─11.FacadePattern │ ├─html │ └─MyFacadePattern │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ └─TempPE │ └─Properties ├─12.FlyweightPattern │ ├─html │ └─MyFlyweightPattern │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ └─TempPE │ └─Properties ├─13.ProxyPattern │ ├─html │ └─MyProxyPattern │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ └─TempPE │ └─Properties ├─14.TemplateMethod │ ├─html │ └─MyTemplateMethod │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ └─TempPE │ └─Properties ├─15.VisitorPattern │ ├─html │ └─MyVisitorPattern │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ └─TempPE │ └─Properties ├─16.StrategyPattern │ ├─html │ └─MyStrategyPattern │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ └─TempPE │ └─Properties ├─17.StatePattern │ ├─html │ └─StatePattern │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ └─TempPE │ └─Properties ├─18.MementoPattern │ ├─html │ └─MementoPattern │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ └─TempPE │ └─Properties ├─19.MediatorPattern │ ├─html │ └─MediatorPattern │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ └─TempPE │ └─Properties ├─20.OberverPattern │ ├─CatOberverPattern │ │ ├─bin │ │ │ └─Debug │ │ ├─obj │ │ │ └─Debug │ │ │ └─TempPE │ │ └─Properties │ ├─html │ └─MyOberverPattern │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ └─TempPE │ └─Properties ├─21.IteratorPattern │ ├─html │ └─IteratorPattern │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ └─TempPE │ └─Properties ├─22.InterpreterPattern │ ├─html │ └─MyInterpreterPattern │ ├─bin │ │ └─Debug │ ├─obj │ │ └─Debug │ │ └─TempPE │ └─Properties └─23.CommandPattern ├─html └─MyCommandPattern ├─bin │ └─Debug ├─obj │ └─Debug │ └─TempPE └─Properties
C#设计模式(1) 一、 C# 面向对象程序设计复习 二、 设计模式举例 三、 先有鸡还是先有蛋? 四、 大瓶子套小瓶子还是小瓶子套大瓶子? 五、 .net本质 C#设计模式(2) 一、 "开放-封闭"原则(OCP) 二、 里氏代换原则(LSP) C#设计模式(3) 三、 依赖倒置原则(DIP) 四、 接口隔离原则(ISP) 五、 合成/聚合复用原则(CARP) 六、 迪米特法则(LoD) C#设计模式(4)-Simple Factory Pattern 一、 简单工厂(Simple Factory)模式 二、 Simple Factory模式角色与结构: 三、 程序举例: 四、 Simple Factory模式演化 五、 优点与缺点: C#设计模式(5)-Factory Method Pattern 一、 工厂方法(Factory Method)模式 二、 Factory Method模式角色与结构: 三、 程序举例: 四、 工厂方法模式与简单工厂模式 五、 Factory Method模式演化 六、 Factory Method模式与其它模式的关系 七、 另外一个例子 C#设计模式(6)-Abstract Factory Pattern 一、 抽象工厂(Abstract Factory)模式 二、 Abstract Factory模式的结构: 三、 程序举例: 四、 在什么情形下使用抽象工厂模式: 五、 抽象工厂的起源 六、 Abstract Factory模式在实际系统中的实现 七、 "开放-封闭"原则 C#设计模式(7)-Singleton Pattern 一、 单例(Singleton)模式 二、 Singleton模式的结构: 三、 程序举例: 四、 在什么情形下使用单例模式: 五、 Singleton模式在实际系统中的实现 六、 C#中的Singleton模式 C#设计模式(8)-Builder Pattern 一、 建造者(Builder)模式 二、 Builder模式的结构: 三、 程序举例: 四、 建造者模式的活动序列: 五、 建造者模式的实现: 六、 建造者模式的演化 七、 在什么情况下使用建造者模式 C#设计模式(9)-Prototype Pattern 一、 原型(Prototype)模式 二、 Prototype模式的结构: 三、 程序举例: 四、 带Prototype Manager的原型模式 五、 浅拷贝与深拷贝 六、 Prototype模式的优点与缺点 C#设计模式(10)-Adapter Pattern 一、 适配器(Adapter)模式 二、 类的Adapter模式的结构: 三、 类的Adapter模式示意性实现: 四、 对象的Adapter模式的结构: 五、 对象的Adapter模式示意性实现: 六、 在什么情况下使用适配器模式 七、 一个实际应用Adapter模式的例子 八、 关于Adapter模式的讨论 C#设计模式(11)-Composite Pattern 一、 合成(Composite)模式 二、 合成模式概述 三、 安全式的合成模式的结构 四、 安全式的合成模式实现 五、 透明式的合成模式结构 六、 透明式的合成模式实现 七、 使用合成模式时考虑的几个问题 八、 和尚的故事 九、 一个实际应用Composite模式的例子 C#设计模式(12)-Decorator Pattern 一、 装饰(Decorator)模式 二、 装饰模式的结构 三、 装饰模式示例性代码 四、 装饰模式应当在什么情况下使用 五、 装饰模式实际应用的例子 六、 使用装饰模式的优点和缺点 七、 模式实现的讨论 八、 透明性的要求 九、 装饰模式在.NET中的应用 C#设计模式(13)-Proxy Pattern 一、 代理(Proxy)模式 二、 代理的种类 三、 远程代理的例子 四、 代理模式的结构 五、 代理模式示例性代码 六、 高老庄悟空降八戒 七、 不同类型的代理模式 八、 代理模式实际应用的例子 设计模式(14)-Flyweight Pattern 一、 享元(Flyweight)模式 二、 单纯享元模式的结构 三、 单纯享元模式的示意性源代码 四、 复合享元模式的结构 五、 一个咖啡摊的例子 六、 咖啡屋的例子 七、 享元模式应当在什么情况下使用 八、 享元模式的优点和缺点 设计模式(15)-Facade Pattern 一、 门面(Facade)模式 二、 门面模式的结构 三、 门面模式的实现 四、 在什么情况下使用门面模式 五、 一个例子 六、 使用门面模式的设计 设计模式(16)-Bridge Pattern 一、 桥梁(Bridge)模式 二、 桥梁模式的结构 三、 桥梁模式的示意性源代码 四、 调制解调器问题 五、 另外一个实际应用Bridge模式的例子 六、 在什么情况下应当使用桥梁模式 设计模式(17)-Chain of Responsibility Pattern 一、 职责链(Chain of Responsibility)模式 二、 责任链模式的结构 三、 责任链模式的示意性源代码 四、 纯的与不纯的责任链模式 五、 责任链模式的实际应用案例 六、 责任链模式的实现 设计模式(18)-Command Pattern 一、 命令Command模式 二、 命令模式的结构 三、 命令模式的示意性源代码 四、 玉帝传美猴王上天 五、 命令模式的实现 六、 命令模式的实际应用案例 七、 在什么情况下应当使用命令模式 八、 使用命令模式的优点和缺点 设计模式(19)-Observer Pattern 一、 观察者(Observer)模式 二、 观察者模式的结构 三、 观察者模式的示意性源代码 四、 C#中的Delegate与Event 五、 一个实际应用观察者模式的例子 六、 观察者模式的优缺点 设计模式(20)-Visitor Pattern 一、 访问者(Visitor)模式 二、 访问者模式的结构 三、 示意性源代码 四、 一个实际应用Visitor模式的例子 五、 在什么情况下应当使用访问者模式 六、 使用访问者模式的优点和缺点 设计模式(21)-Template Method Pattern 一、 模板方法(Template Method)模式 二、 模版方法模式的结构 三、 模板方法模式的示意性代码 四、 继承作为复用的工具 五、 一个实际应用模板方法的例子 六、 模版方法模式中的方法 七、 重构的原则 设计模式(22)-Strategy Pattern 一、 策略(Strategy)模式 二、 策略模式的结构 三、 示意性源代码 四、 何时使用何种具体策略角色 五、 一个实际应用策略模式的例子 六、 在什么情况下应当使用策略模式 七、 策略模式的优点和缺点 八、 其它

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值