通俗易懂设计模式解析——命令模式
前言
今天我们一起来看行为型设计模式中的命令模式、何为命令模式呢?先谈命令——我现在需要对某一条信息进行删除,我进行点击删除按钮。后台执行删除的命令、对信息进行删除。那么我们要讲的命令模式又是什么呢?命令模式就是把一个操作或者行为抽象为一个对象。然后通过对命令的抽象化来使得发出命令的职责和执行命令的职责分隔开。简单来说命令模式就是解决命令的请求者和命令的执行者之间的耦合关系的。
命令模式介绍
一、来由
在我们开发软件系统的时候,命令的请求者和命令的执行者是属于紧耦合的状态。但是对于某些特殊场合这么一种紧耦合的状态就不合适了。例如对行为命令的”日志记录、撤销/恢复、命令的队列”等操作就不太合适了。那么在这些情况下如何对这些命令进行统一的管理呢?实现其松耦合呢?
二、意图
将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。
三、案例图
四、命令模式代码示例
我们看上面的案例图可以看到命令模式是包含了以下五个部分的:
客户角色:创建具体的命令对象并确定命令对象的接收者
命令请求者:命令模式中最重要的角色、持有命令对象、实现对命令的控制、要求命令对象执行请求
命令接收者:真正的命令的执行者、实现具体功能
命令角色:声明所有的命令的一个抽象类
具体命令角色:命令接口实现对象、持有命令接收者、调用接收者完成命令的执行
在我们日常软件开发过程中必定会涉及到信息的增删改查、一般的信息进行操作也就罢了。但是对于一些重要的信息进行操作的时候我们是否就需要对其进行控制了。比如对其操作的日志的记录。对操作命令的撤销恢复。这里我们看看如何使用命令模式来对命令进行控制操作:
namespace command_pattern { class commandpattern { } #region 命令接收者——具体操作 =================== /// <summary> /// 执行命令 /// </summary> public class inforeceiver { public void delete() { console.writeline("删除了第一条信息!"); } public void update() { console.writeline("更新了第二天信息!"); } } #endregion #region 命令请求者——控制命令 =================== /// <summary> /// 控制命令调用请求 /// </summary> public class infoinvoke { /// <summary> /// 记录上一个命令 /// </summary> private command lastcommand =null; /// <summary> /// 接收当前命令 /// </summary> private command _command = null; public infoinvoke(command command=null) { this._command = command; } public string executeinvoke() { if (_command==null&& lastcommand==null) return ("无命令执行!"); if (_command == null) { console.writeline($"记录此操作记录{_command.gettype().name}的撤销操作!"); _command = lastcommand; return ("执行撤销操作!"); } console.writeline($"记录此操作记录{_command.gettype().name}!"); _command.execute(); return ("执行成功!"); } } #endregion #region 命令角色——抽象命令 ===================== /// <summary> /// 抽象命令 持有命令接收者,调用接收者执行命令 /// </summary> public abstract class command { protected inforeceiver _inforeceiver; public command(inforeceiver inforeceiver) { this._inforeceiver = inforeceiver; } public abstract void execute(); } #endregion #region 具体命令角色——调用接收者 =============== /// <summary> /// 实现抽象角色 /// </summary> public class infocommanddelete : command { public infocommanddelete(inforeceiver inforeceiver) : base(inforeceiver) { } public override void execute() { _inforeceiver.delete(); } } #endregion #region 具体命令角色——调用接收者 =============== /// <summary> /// 实现抽象角色 /// </summary> public class infocommandupdate : command { public infocommandupdate(inforeceiver inforeceiver) : base(inforeceiver) { } public override void execute() { _inforeceiver.update(); } } #endregion }
namespace command_pattern { class program { static void main(string[] args) { ///初始化命令接收者和命令请求者还有具体命令 inforeceiver inforeceiver = new inforeceiver(); infocommanddelete infocommanddelete = new infocommanddelete(inforeceiver); infoinvoke infoinvoke = new infoinvoke(infocommanddelete); var result=infoinvoke.executeinvoke(); console.writeline(result); } } }
使用场景及优缺点
在命令模式中重点就是实现将“行为请求者”和“行为实现者”之间进行解耦。而在命令请求者角色中可以对具体命令角色做一定的控制、同时也可以保存其额外的状态信息。
一、使用场景
1、认为是命令的地方都可以使用命令模式
2、系统支持命令的撤销/恢复、重新执行等操作的时候可以考虑使用命令模式
3、命令的发送者和命令执行者有不同的生命周期,不要求命令发送必须立马执行
4、命令需要进行管理控制时
二、优点
1、降低了系统的耦合性
2、新的命令可以很容易添加到系统中
3、可以将命令组合在一起形成合成命令
4、可以设计实现撤销、重新执行的操作
三、缺点
1、使用命令模式可能导致有过多的具体命令类、这样会使系统变得不切实际。
总结
到这里我们就介绍完了命令模式。总的来说命令模式是将”行为请求者”和”行为实现者”进行了解耦。解耦之后就方便对命令进行控制管理(操作信息日志记录、撤销/恢复操作、重新操作、命令队列等等)。同时对新的命令加入也方便了一些(方便对命令扩展)。
一个人如若不能使自己的人生辉煌,但也没有理由使它黯淡;人生可以平凡,但不可以庸俗、堕落;人生不在乎掠取多少,而在于追求过程的完美与卓越!
欢迎大家扫描下方二维码,和我一起踏上设计模式的闯关之路吧!