C#设计模式读书笔记之命令模式(Command Pattern)
原创
©著作权归作者所有:来自51CTO博客作者4562xse3460的原创作品,请联系作者获取转载授权,否则将追究法律责任
命令模式(Command Pattern)【使用频率:★★★★☆】
1. 概述
将一个请求封装为一个对象,从而让我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。命令模式是一种对象行为型模式,其别名为动作(Action)模式或事务(Transaction)模式。
命令模式的本质就在于将命令进行封装,将发出命令的责任和执行命令的责任分开。
2. 模式中的角色
2.1 Command(抽象命令类):抽象命令类一般是一个抽象类或接口,在其中声明了用于执行请求的execute()等方法,通过这些方法可以调用请求接收者的相关操作。
2.2 ConcreteCommand(具体命令类):具体命令类是抽象命令类的子类,实现了在抽象命令类中声明的方法,它对应具体的接收者对象,将接收者对象的动作绑定其中。在实现execute()方法时,将调用接收者对象的相关操作(Action)。
2.3 Invoker(调用者):调用者即请求发送者,它通过命令对象来执行请求。一个调用者并不需要在设计时确定其接收者,因此它只与抽象命令类之间存在关联关系。在程序运行时可以将一个具体命令对象注入其中,再调用具体命令对象的execute()方法,从而实现间接调用请求接收者的相关操作。
2.4 Receiver(接收者):接收者执行与请求相关的操作,它具体实现对请求的业务处理。
3. 模式解读
3.1 模式的类图
3.2 代码实现
这里以电视机为例。电视剧是请求的接受者,遥控器是请求的发送者,遥控器上有一些按钮,不同的按钮对应着不同的操作。在这里遥控器需要执行三个命令:打开电视机、关闭电视机、换台。
using System;
namespace ConsoleApp2
{
class Class12
{
public static void Main(string[] args)
{
ICommand openCommand, closeCommand, changeCommand;
openCommand = new OpenTvCommand();
closeCommand = new CloseTvCommand();
changeCommand = new ChangeChannelCommand();
Invoker invoker = new Invoker(openCommand, closeCommand, changeCommand);
invoker.Open(); //打开电视机
invoker.ChangeChannel(); //换频道
invoker.ChangeChannel();
invoker.ChannelUndo();
invoker.ChannelUndo();
invoker.ChannelUndo();
invoker.Close(); //关闭电视机
Console.ReadLine();
}
}
// 抽象命令接口
public interface ICommand
{
void Execute(int i);
}
// 具体命令类
public class OpenTvCommand : ICommand
{
private Television m_Tv;
public OpenTvCommand()
{
m_Tv = new Television();
}
public void Execute(int i)
{
m_Tv.Open();
}
}
// 具体命令类
public class ChangeChannelCommand : ICommand
{
private Television m_Tv;
public ChangeChannelCommand()
{
m_Tv = new Television();
}
public void Execute(int i)
{
m_Tv.ChangeChannel(i);
}
}
// 具体命令类
public class CloseTvCommand : ICommand
{
private Television m_Tv;
public CloseTvCommand()
{
m_Tv = new Television();
}
public void Execute(int i)
{
m_Tv.Close();
}
}
// 接收者
public class Television
{
public void Open()
{
Console.WriteLine("打开电视机......");
}
public void Close()
{
Console.WriteLine("关闭电视机......");
}
public void ChangeChannel(int i)
{
Console.WriteLine("切换电视频道......现在是频道" + i);
}
}
// 调用者
public class Invoker
{
private ICommand m_OpenTVCommand;
private ICommand m_CloseTVCommand;
private ICommand m_ChangeChannelCommand;
public int m_NowChannel = 0; //当前频道
public int m_PreviousChannel; //前一个频道,用于执行返回操作
public Invoker(ICommand openTvCommand, ICommand closeTvCommand, ICommand changeChannelCommand)
{
m_OpenTVCommand = openTvCommand;
m_CloseTVCommand = closeTvCommand;
m_ChangeChannelCommand = changeChannelCommand;
}
// 打开电视剧
public void Open()
{
m_OpenTVCommand.Execute(0);
}
// 关闭电视机
public void Close()
{
m_CloseTVCommand.Execute(0);
}
// 换频道
public void ChangeChannel()
{
// 换频道前记录当前频道
m_PreviousChannel = m_NowChannel;
// 频道+1
m_NowChannel++;
m_ChangeChannelCommand.Execute(m_NowChannel);
}
// 频道返回
public void ChannelUndo()
{
// 将以前的频道传入
m_ChangeChannelCommand.Execute(m_PreviousChannel);
// 当前频道与前一个频道进行互换
int tempChannel;
tempChannel = m_PreviousChannel;
m_PreviousChannel = m_NowChannel;
m_NowChannel = tempChannel;
}
}
}
4、模式优缺点
4.1 优点
- 降低了系统耦合度
- 新的命令可以很容易添加到系统中去。
4.2 缺点
使用命令模式可能会导致某些系统有过多的具体命令类。
5、模式使用场景
- 系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
- 系统需要在不同的时间指定请求、将请求排队和执行请求。
- 系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。
- 系统需要将一组操作组合在一起,即支持宏命令。