架构演化学习思考(3)
架构演化学习思考(3)
接上一篇我们继续对命令模式进行学习。
在这节内容中,我们聊一下经典的命令模式,还记得上一篇文章开头我们实现的简单的命令模式吗?来看代码,非常简单易解。
public interface ICommand { void Execute(); } public class PlayMusicCommand : ICommand { public void Execute() { Debug.Log("你说家是唯一的城堡,随着稻香一路奔跑~"); } } var Start() { var command = new PlayMusicCommand(); command.Execute(); }
以上最简的命令模式中,我们可以分离出一些角色。
ICommand:接口 对应经典命令模式中的 Command的角色
PlayMusicCommand:类 继承接口,是接口的具体实现,对应经典命令模式中的ConcreteCommand角色。
Start方法:是命令的发出者,对应经典命令模式中的Invoker角色
由此我们提炼实现经典命令模式的三个角色。
经典命令模式的实现完善
还差一个Receiver,即命令的接收者或执行者,组成经典命令模式的四种(也有说五种)角色:
- Command:抽象命令(命令接口)
- ConcreteCommand:具体命令
- Invoker:命令的调用者,发起者,触发者。
- Receiver:命令的接收者,被Command访问和操作。
- 客户端:创建具体命令对象并设置其接收者,将命令对象交给调用者执行(如果涉及到5部分的话)
我们还以商品购买为例,用以上涉及到的角色方式来实现购买货品这样一个操作。
namespace TestCommand { //售货员 对应Receiver public class Salesperson { public void SellGoods(int id,int count) { for (int i = 1; i <= count; i++) { Debug.Log($"编号为{id}的商品售出1件!"); } Debug.Log($"编号为{id}的商品总售出{count}件!"); } } //命令接口 对应Command public interface Command { void Execute(); } //具体实现 对应ConcreteCommand 具体命令 public class BuyCommand : Command { public Salesperson salesPerson; public int goodsId; public int count; public void Execute() { salesPerson.SellGoods(goodsId,count); } } //触发者 命令的发送者 //顾客 public class Customer { private List<Command> mCommands = new List<Command>(); public void AddCommand(Command command) { mCommands.Add(command); } //触发命令 public void triggerCommands() { mCommands.ForEach(command=>command.Execute()); mCommands.Clear(); } } //客户端角色 void Start() { var customer = new Customer(); var salesperson = new Salesperson(); //2 号商品购买五件 的命令 customer.AddCommand(new BuyCommand() { salesPerson = salesperson, goodsId = 2, count = 5 }); //让顾客发出购买命令 customer.triggerCommands(); } }
其大体思路如下:对应着经典命令模式的五部分
终于将经典模式的五部分实现完整了,命令模式梳理到这里差不多结束了,那么这对架构设计有啥启发和应用思考呢?
当然有。
在项目中,我们对位于底层部分的数据模块访问时就可以应用命令模式,Recever为底层的System或者数据Model,ConCreteCommand为对应的具体操作(对数据进行查和改、解锁成就系统的成就),而触发器Involver则是架构,也就是说整个项目的依赖关系的总掌控者,而客户端则对应表现层的控制逻辑。
不知道有没有对”架构“这个触发者的认知有没有更加具体一些呢?
笔者是这样理解”架构“的身份的,好比是一个交换机接线员,当我们需要和朋友电话时候,则要拿起自己这边的话筒传呼接线员,告诉TA自己朋友的电话机号,然后接通之后,完成我们对朋友交流的需求。当然这个例子不一定十分准确,但很大程度上让大家对”架构“的认识没有那么抽象。
好,在回到经典模式,来看一看此模式有什么好处。
命令模式的好处
好处之一是将Invoker和Receiver完全解耦。
那这个功能好像观察者模式也可以实现吧,那么和观察者模式对比有些不同呢?答案还在命令本身,命令除了将invoker和receiver解耦,还可以进行自由扩展。我可以购买、也可以退货,也可以更换商品等等一些操作。当然从Invoker这边可以对命令进行存储(使用堆或者栈或者List等容器),进而可以实现回退复原、行为树等功能。
关于命令模式的另一点思考:
我们将视角聚焦在命令模式的Command中,也就是结构图上的”订单模板“。有了模板就好进行拓展,这里简单聊聊,命令模式中的开闭原则。
命令模式中的开闭原则
开闭原则大家比较熟悉:
开闭原则:一个类应当对扩展开放、对修改关闭
当一个结构模块或系统开发成型之后,除非遇到一些bug或者功能缺陷,否则不应该对结构模块或者系统进行修改,这就是对修改关闭。而需要新增加功能或者拓展时候,可以通过扩展的方式来添加一些功能,也就是对扩展开放。
而根据命令模式中的各个角色,在拓展功能时候有着不同的准则和作用:
- Invoker:关闭修改
- Recever:关闭内部修改
- Command: 拓展的标准
- ConcreteCommand :开放实现的拓展
笔者的项目功底尚浅,只是简单的聊一下涉及到开闭原则,愿大家多写代码多实践,
慢慢将这些思考在实际项目中有所应用和体验,逐步提高自己的编程和架构设计能力。
好,关于命令模式我们就聊到这里了,接下来还会继续更新此系列内容,谢谢各位与我一起思考和体悟!
本文作者:畅知
本文链接:https://www.cnblogs.com/TonyCode/p/18337666
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步