首页 > 其他分享 >架构演化学习思考(3)

架构演化学习思考(3)

时间:2024-08-01 21:50:36浏览次数:15  
标签:架构 演化 void 模式 命令 Command 思考 command public

架构演化学习思考(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();
    }

}

其大体思路如下:对应着经典命令模式的五部分

image

终于将经典模式的五部分实现完整了,命令模式梳理到这里差不多结束了,那么这对架构设计有啥启发和应用思考呢?

当然有。

在项目中,我们对位于底层部分的数据模块访问时就可以应用命令模式,Recever为底层的System或者数据Model,ConCreteCommand为对应的具体操作(对数据进行查和改、解锁成就系统的成就),而触发器Involver则是架构,也就是说整个项目的依赖关系的总掌控者,而客户端则对应表现层的控制逻辑。

不知道有没有对”架构“这个触发者的认知有没有更加具体一些呢?

笔者是这样理解”架构“的身份的,好比是一个交换机接线员,当我们需要和朋友电话时候,则要拿起自己这边的话筒传呼接线员,告诉TA自己朋友的电话机号,然后接通之后,完成我们对朋友交流的需求。当然这个例子不一定十分准确,但很大程度上让大家对”架构“的认识没有那么抽象。

好,在回到经典模式,来看一看此模式有什么好处。

命令模式的好处

好处之一是将Invoker和Receiver完全解耦。

那这个功能好像观察者模式也可以实现吧,那么和观察者模式对比有些不同呢?答案还在命令本身,命令除了将invoker和receiver解耦,还可以进行自由扩展。我可以购买、也可以退货,也可以更换商品等等一些操作。当然从Invoker这边可以对命令进行存储(使用堆或者栈或者List等容器),进而可以实现回退复原、行为树等功能。

关于命令模式的另一点思考:

我们将视角聚焦在命令模式的Command中,也就是结构图上的”订单模板“。有了模板就好进行拓展,这里简单聊聊,命令模式中的开闭原则。

命令模式中的开闭原则

开闭原则大家比较熟悉:

开闭原则:一个类应当对扩展开放、对修改关闭

当一个结构模块或系统开发成型之后,除非遇到一些bug或者功能缺陷,否则不应该对结构模块或者系统进行修改,这就是对修改关闭。而需要新增加功能或者拓展时候,可以通过扩展的方式来添加一些功能,也就是对扩展开放。

而根据命令模式中的各个角色,在拓展功能时候有着不同的准则和作用:

  • Invoker:关闭修改
  • Recever:关闭内部修改
  • Command: 拓展的标准
  • ConcreteCommand :开放实现的拓展

笔者的项目功底尚浅,只是简单的聊一下涉及到开闭原则,愿大家多写代码多实践,

慢慢将这些思考在实际项目中有所应用和体验,逐步提高自己的编程和架构设计能力。

好,关于命令模式我们就聊到这里了,接下来还会继续更新此系列内容,谢谢各位与我一起思考和体悟!

标签:架构,演化,void,模式,命令,Command,思考,command,public
From: https://www.cnblogs.com/TonyCode/p/18337666

相关文章

  • 1000W长连接,如何建立和维护?千万用户IM 架构设计
    文章很长,且持续更新,建议收藏起来,慢慢读!疯狂创客圈总目录博客园版为您奉上珍贵的学习资源:免费赠送:《尼恩Java面试宝典》持续更新+史上最全+面试必备2000页+面试必备+大厂必备+涨薪必备免费赠送:《尼恩技术圣经+高并发系列PDF》,帮你实现技术自由,完成职业升级,薪......
  • 在淘客返利系统中使用Kafka实现事件驱动架构
    在淘客返利系统中使用Kafka实现事件驱动架构大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!今天我们来探讨如何在淘客返利系统中使用Kafka实现事件驱动架构,以提高系统的可扩展性和灵活性。一、什么是事件驱动架构事件驱动架构(Event-DrivenArchit......
  • 洛谷P3161 [CQOI2012] 模拟工厂 贪心策略的思考
    P3161[CQOI2012]模拟工厂传送门:模拟工厂问题描述:初始的生产力和商品分别为1和0。每一个时刻可以选择两个动作:生产力+1或者生产生产力数量的商品。现在有很多个订单,每个订单有三个部分:时间t,需要多少商品p,可以获得的价值v。现在需要决定各个时刻的动作选择,以及订单是否接取,以期......
  • 同城交友搭伴App小程序开发需求与功能架构概览
    一、开发需求分析目标用户定位同城社区交友找搭子app小程序的目标用户主要是追求同城社交、寻找共同兴趣或活动伙伴的群体。这些用户可能包括年轻人、职场人士、兴趣爱好者等,他们希望通过平台结识新朋友、扩大社交圈,并找到志同道合的搭子共同参与活动。用户需求分析社交需求:......
  • MongoDB两地三中心集群架构设计、全球多写集群架构设计
    文章目录高级集群架构设计两地三中心集群架构设计容灾级别两地三中心方案:复制集跨中心部署两地三中心部署的考量点两地三中心复制集搭建环境准备整体架构配置域名解析启动5个MongoDB实例初始化复制集配置选举优先级启动持续写脚本(每2秒写一条记录)测试结果总结全球多......
  • Grafana Loki 架构详解,比 ES 成本低很多
    在本指南中,我们将详细了解GrafanaLoki架构及其组件。在公司的分布式环境中,存储和管理来自各种系统资源的日志是一项具有挑战性的任务。为了简化这项任务,引入了一个称为日志聚合的概念,它从各种系统资源中收集、存储、管理日志。有各种各样的日志聚合工具,其中一个工具是GrafanaL......
  • 基于 KubeSphere 的 Kubernetes 生产环境部署架构设计及成本分析
    转载:基于KubeSphere的Kubernetes生产环境部署架构设计及成本分析 前言导图1.简介1.1架构概要说明今天分享一个实际小规模生产环境部署架构设计的案例,该架构设计概要说明如下:本架构设计适用于中小规模(<=50)的Kubernetes生产环境,大型环境没有经验,有待验证。......
  • C++对象析构顺序问题——由QObject::desroyed展开的思考
    C++对象析构顺序问题——由QObject::desroyed展开的思考C++析构函数执行的顺序是最先执行继承链最末端的子类的,最后执行顶层的基类的。而QObject::destroyed(QObject*obj=nullptr)信号在Qt文档中说是“在obj被完全析构时之前立即触发,并且不会被阻塞”。这里的“完全析......
  • 架构演化思考总结(2)
    架构演化思考总结(2)​ —-–从命令模式中来探索处理依赖关系在正式引入命令模式的概念之前,我们先从简单的案例来逐步演化大家在书面上常见到的内容。publicinterfaceICommand{voidExecute();}publicclassPlayMusicCommand:ICommand{publicvoid......
  • 【系统架构设计师】二十一、面向服务架构设计理论与实践②
    目录四、SOA主要协议和规范五、SOA设计的标准要求5.1SOA设计标准5.2服务质量六、 SOA的作用与设计原则七、SOA的设计模式7.1服务注册表模式7.2企业服务总线模式7.3微服务模式八、SOA的构建与实施8.1构建SOA时应该注意的问题8.2SOA的实施过程8.3 业务......