用心理解设计模式——命令模式 (Commond Pattern)

前置文章: 设计模式的原则 

其他设计模式:用心理解设计模式

设计模式相关代码已统一放至 我的 Github

 

一、定义

  行为型模式之一。

  Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.

  (将请求封装为对象,从而让你用不同的请求、队列、日志请求,将客户端参数化,并且支持撤销操作)

二、结构解析

  命令模式的一般结构有四种角色:抽象命令,具体命令,实现者,调用者。或者也可认为有五个角色,多一个客户(装配者)。

  抽象命令(Command):负责定义一个命令执行的接口方法。

  具体命令(ConcreteCommand):关联/持有实现者,并在实现的命令执行接口方法中,对实现者提供的功能接口进行组织,形成具体命令

  实现者(Implementor):或叫做 接收者(Receiver),它是命令的实际执行者。只做自己的事,暴露出自己能提供的功能接口,不关心命令。

  调用者(Invoker):使用命令对象的入口,让命令开始执行,可能聚合/持有了N条命令。只关心发出怎样的命令。

三、评价

  命令模式解决了调用者在产生新命令时,都得修改实现者(实现者在内部根据输入命令的不同做不同处理)的问题。

  它的核心思想是 “调用者在接受命令后,反调命令自备处理方法”。请参考 消除程序中的 if else(二),实际就是使用了 策略模式

  “命令” 中的执行方法就是策略,策略由实现者提供的功能组织而成。

  命令新增时实现者将保持不变(除非它提供的功能方法不能通过一定组织实现新的命令)。符合符合开闭原则。

四、额外思考

  Unity 的 事件系统/消息系统 就是使用的命令模式。

  1、定义抽象实现者,定义实现者可提供的功能接口,(需要继承 IEventSystemHandler )。

using UnityEngine.EventSystems;

public interface IDoSth : IEventSystemHandler
{
    //接收到消息/命令时,可执行的事情。只关心自己能做什么
    void DoSth1();
    void DoSth2();
} 

  2、定义具体实现者,实现1中定义的接口。(需要继承MonoBehaviour)

public class Implementor : MonoBehaviour, IDoSth
{
    public void DoSth1() { Debug.Log("DoSth1"); } 
    public void DoSth2() { Debug.Log("DoSth2"); }
}

  3、定义调用者装配命令(下面 Lambda表达式中,对实现者提供的功能接口进行组织,形成具体命令),并执行。

public class Invoker : MonoBehaviour
{
    private void Start()
    {
        ExecuteEvents.Execute<IDoSth>(this.gameObject, null, (t, eventData)=> {
            t.DoSth1();
            t.DoSth2(); 
        });
    }
}

  注意:此例中的 命令对象,实际就是这个Lambda表达式, 其类型(委托) 为 UnityEngine.EventSystems.ExecuteEvents.EventFunction, 该委托的参数1是实现者对象,参数2是额外的事件执行参数。

五、实现

namespace Commond
{
    //命令实现者,做自己的事,不关心命令
    public class Implementor
    {
        public void DoSthX() { }
        public void DoSthY() { }
        public void DoSthZ() { }
    }

    //抽象命令
    public abstract class Command
    {
        public abstract void Execute();
    }

    //具体命令A
    public class ConcreteCommandA : Command
    {
        //持有实现者
        private Implementor implementor;
        public ConcreteCommandA(Implementor implementor)
        {
            this.implementor = implementor;
        }

        public override void Execute()
        {
            //组织实现者的功能,实现具体命令
            //例如这里要使用实现者的XY功能方法
            this.implementor.DoSthX();
            this.implementor.DoSthY();
        }
    }

    //具体命令B
    public class ConcreteCommandB : Command
    {
        private Implementor implementor;
        public ConcreteCommandB(Implementor implementor)
        {
            this.implementor = implementor;
        }

        public override void Execute()
        {
            //组织实现者的功能,实现具体命令
            //例如这里要使用实现者的Z功能方法
            this.implementor.DoSthZ();
        }
    }

    //命令调用者
    public class Invoker
    {
        //聚合持有命令,这里简化为参数方式传入
        public void Invoke(Command command)
        {
            command.Execute();
        }
    }

    //客户,命令装配
    public class Client
    {
        public Client()
        {
            //构造命令实现者
            Implementor implementor = new Implementor();
            //装配具体命令, 将命令实现者与具体命令关联
            ConcreteCommandA concreteCommandA = new ConcreteCommandA(implementor);
            ConcreteCommandB concreteCommandB = new ConcreteCommandB(implementor);
            //构造命令调用者
            Invoker invoker = new Invoker();
            //命令作为参数,提供给命令调用者
            invoker.Invoke(concreteCommandA);
            invoker.Invoke(concreteCommandB);
        }
    }
}

五、撤销操作

  TODO

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

NRatel

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值