首页 星云 工具 资源 星选 资讯 热门工具
:

PDF转图片 完全免费 小红书视频下载 无水印 抖音视频下载 无水印 数字星空

架构演化学习思考(3)

编程知识
2024年08月01日 20:50

架构演化学习思考(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 :开放实现的拓展

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

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

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

From:https://www.cnblogs.com/TonyCode/p/18337666
本文地址: http://shuzixingkong.net/article/679
0评论
提交 加载更多评论
其他文章 运行期加载时共享库路径搜索优先级实验
目录前言实验环境目录说明单独测试不配置路径默认路径ld.so.cacheRUNPATHLD_LIBRARY_PATHRPATH优先级测试附录库文件源码主程序源码makefile脚本run_nonerun_defaultrun_ld_so_cacherun_runpathrun_ld_library_
LangChain的LCEL和Runnable你搞懂了吗
LangChain的LCEL估计行业内的朋友都听过,但是LCEL里的RunnablePassthrough、RunnableParallel、RunnableBranch、RunnableLambda又是什么意思?什么场景下用?
LangChain的LCEL和Runnable你搞懂了吗 LangChain的LCEL和Runnable你搞懂了吗 LangChain的LCEL和Runnable你搞懂了吗
Jenkins 配置即代码(Configuration as Code)详解
1、概述 在《Centos7下安装配置最新版本Jenkins(2.452.3)》这篇博文中讲解了如何安装Jenkins,虽然在安装Jenkins时安装了一些必备的推荐插件,但在企业环境中使用Jenkins之前,我们仍需完成一系列手动配置工作,如配置 System Configuration、Secu
Jenkins 配置即代码(Configuration as Code)详解 Jenkins 配置即代码(Configuration as Code)详解 Jenkins 配置即代码(Configuration as Code)详解
Vue Hook 封装通用型表格
一、创建通用型表格的需求 实现一个通用型表格组件,具备以下功能: 动态列配置。 分页功能。 排序功能。 可扩展的行操作功能。 二、设计通用型表格组件 首先,需要设计一个基础的表格组件,它接受列配置、数据和分页信息等参数。 1. 创建 useTable Hook 在 src/hooks 目录下创建 u
P5665 [CSP-S2019] 划分
讲解 P5665 [CSP-S2019] 划分。 由朴素 dp 入手,先用二分优化,然后用走指针优化,之后注意到单调性,将状态数压缩,然后使用单调队列优化转移。
如何通过PowerShell批量修改O365用户的office phone属性值
我的博客园:https://www.cnblogs.com/CQman/ 如何通过PowerShell批量修改O365用户的office phone属性值? 需求信息: 组织中的O365用户在创建时,已手动录入了办公电话(Office phone),现在需要在办公电话前面加上统一的数字,如“0571
如何通过PowerShell批量修改O365用户的office phone属性值 如何通过PowerShell批量修改O365用户的office phone属性值 如何通过PowerShell批量修改O365用户的office phone属性值
前端使用 Konva 实现可视化设计器(19)- 连接线 - 直线、折线
本章响应小伙伴的反馈,除了算法自动画连接线(仍需优化完善),实现了可以手动绘制直线、折线连接线功能。
前端使用 Konva 实现可视化设计器(19)- 连接线 - 直线、折线 前端使用 Konva 实现可视化设计器(19)- 连接线 - 直线、折线 前端使用 Konva 实现可视化设计器(19)- 连接线 - 直线、折线
SLF4J2.0.x与Logback1.3.x的绑定变动还是很大的,不要乱点鸳鸯谱
开心一刻 今天跟我姐聊天 我:我喜欢上了我们公司的一个女同事,她好漂亮,我心动了,怎么办 姐:喜欢一个女孩子不能只看她的外表 我:我知道,还要看她的内在嘛 姐:你想多了,还要看看自己的外表 背景介绍 在 SpringBoot2.7 霸王硬上弓 Logback1.3 → 不甜但解渴 原理分析那部分,我
SLF4J2.0.x与Logback1.3.x的绑定变动还是很大的,不要乱点鸳鸯谱 SLF4J2.0.x与Logback1.3.x的绑定变动还是很大的,不要乱点鸳鸯谱 SLF4J2.0.x与Logback1.3.x的绑定变动还是很大的,不要乱点鸳鸯谱