设计模式之命令模式

时间:2024-03-01 21:23:54

命令模式介绍

命令

命令模式最初的感受是把逻辑实现与操作请求进行分离,降低耦合方便扩展。

命令模式是一种行为模式,以数据驱动的方式将命令对象,通过构造函数的形式传递给调用者。调用者再提供相应的实现为命令执行提供操作方法。

命令场景的核心的逻辑是调用方不需要去关心具体的逻辑实现,它只管调用它需要的模块,而被调用方也不需要关心被谁调用,它只负责完成模块的实现就行。

命令模式的使用场景需要分为三个比较大的块:命令、实现、调用者,而这三块内容的拆分也是选择适合场景的关键因素,经过这样的拆分可以让逻辑具备单一职责的性质,便于扩展。

命令模式可将请求转换为一个包含与请求相关的所有信息的独立对象。该转换让你能根据不同的请求将方法参数化、延迟请求执行或将其放入队列中且能实现可撤销操作。

优秀的软件设计通常会将关注点进行分离,而这往往会导致软件的分层。

命令模式的结构

  • 发送者

    也可叫触发者,负责对请求进行初始化,其中必须包含一个成员变量来存储对于命令对象的引用。发送者触发命令,而不向接收者直接发送请求。

  • 命令

    通常仅声明一个执行命令的方法

  • 具体命令

    实现各种类型的请求。具体命令自身并不完成工作,而是会将委派给一个业务逻辑对象。

  • 接收者

    包含部分业务逻辑,几乎任何对象都可以作为接收者。绝大部分命令只处理如何将请求传递到接收者的细节,接收者自己会完成实际的工作。

  • 客户端

    创建并配置具体命令对象。客户端必须将包括接收者实体在内的所有请求传递给命令的构造函数。

适用场景

  • 通过操作来参数化对象
  • 想将操作放入队列中、操作的执行或者远程执行操作
  • 实现操作回滚功能

命令模式的实现方式

1、声明仅有一个执行方法的命令接口。

2、抽取请求并使之成为实现命令接口的具体命令类。每个类都必须有一组成员变量来保存请求参数和对于实际接收者对象的引用。

3、找到担任发送者职责的类,在这些类中添加保存命令的成员变量。发送者只能通过命令接口与其命令进行交互。发送者自身通常并不创建命令对象,而是通过客户端代码获取。

4、修改发送者使其执行命令,而非直接将请求发送给接收者。

5、客户端必须按照以下顺序来初始化对象。

  • 创建接收者
  • 创建命令
  • 创建发送者并将其与特定命令关联

Demo

命令模式可以通过抽象或接口类型(发送者)中的行为方法来识别,该类型调用另一个不同的抽象或接口类型(接收者)实现中的方法,该实现则是在创建时由命令模式的实现封装。

接口与实现类

    /// <summary>
    /// 简单命令    实现命令接口
    /// </summary>
    class SimpleCommand : ICommand
    {
        private string _info;

        public SimpleCommand(string message)
        {
            this._info = message;
        }
        public void Execute()
        {
            Console.WriteLine("执行简单命令,"+_info);
        }        
    }

    /// <summary>
    /// 复杂命令    实现命令接口
    /// </summary>
    class ComplexCommand : ICommand
    {
        Receiver _receiver;
        private string _complexOneInfo;

        private string _complexTwoInfo;

        public ComplexCommand(Receiver receiver,string oneInfo,string twoInfo)
        {
            _receiver = receiver;
            _complexOneInfo = oneInfo;
            _complexTwoInfo = twoInfo;
        }

        public void Execute()
        {
            Console.WriteLine("执行复杂命令");
            _receiver.DoOne(_complexOneInfo);
            _receiver.DoTwo(_complexTwoInfo);
        }
    }

接收者

    /// <summary>
    /// 接收者
    /// </summary>
    class Receiver 
    {
        public void DoOne(string oneInfo) 
        {
            Console.WriteLine("接收的信息为:"+oneInfo);
        }

        public void DoTwo(string oneInfo) 
        {
            Console.WriteLine("接收的信息为:" + oneInfo);
        }
    }

调用者

    /// <summary>
    /// 调用者Invoker 
    /// </summary>
    public class InvokerClient
    {
        private ICommand _one;
        private ICommand _two;

        public void SetOnOne(ICommand com) 
        {
            _one = com;
        }

        public void SetOnTwo(ICommand com) 
        {
            _two = com;
        }

        public void DoExecute() 
        {
            Console.WriteLine("调用者One的打印");
            if (_one is ICommand)
            {
                _one.Execute();
            }

            Console.WriteLine("调用者Two的打印");
            if (_two is ICommand)
            {
                _two.Execute();
            }                 
        }
    }

实现结果

此模式在执行一些业务逻辑比较条理化的需求时,可以被使用。通过将业务中的链条关系,整合成一个个命令,调用者直接调用对应的命令接口就行,根本不需要知道是谁,如何提供的方法。而且实现方法的人也不知道谁调用的,如何调用的,这些对于它们来说都是不相关的,也满足单一职责和开闭原则。

小寄语

原创不易,给个关注呗。

人生短暂,我不想去追求自己看不见的,我只想抓住我能看的见的。

我是阿辉,感谢您的阅读,如果对你有帮助,麻烦关注、点赞、转发 谢谢。