美文网首页
游戏设计模式【命令模式】

游戏设计模式【命令模式】

作者: 语文小子 | 来源:发表于2016-10-01 11:22 被阅读0次

    定义:将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能

    Command类:是一个抽象类,类中对需要执行的命令进行声明,一般来说要对外公布一个execute方法用来执行命令和undo撤销操作
    ConcreteCommand类:Command类的实现类,对抽象类中声明的方法进行实现
    Client类:最终的客户端调用类

        以上三个类的作用应该是比较好理解的,下面我们重点说一下Invoker类和Recevier类。
    

    Invoker类:命令的指挥者,负责设置命令和发起命令
    Receiver类:执行命令具体操作的对象

    以下以一个游戏例子来展示

    class Actor {
    private:
        int x, y;
    public:
        Actor() { x = 0; y = 0; }
        int getX() { return x; }
        int getY() { return y; }
        void moveTo(int x, int y) { this->x = x; this->y = y; cout << x << "," << y << endl; }
    };
    
    class Command{
    public:
      virtual ~Command(){}
      virtual void execute() = 0;
      virtual void undo() = 0;
    };
    
    class MoveCommand : public Command{
    class MoveCommand : public Command {
    public:
        MoveCommand(Actor *actor, int x, int y) {
            m_x = x;
            m_y = y;
            m_actor = actor;
        }
        void execute() {
            m_beforeX = m_actor->getX();
            m_beforeY = m_actor->getY();
    
            m_actor->moveTo(m_x, m_y);
        }
        void undo() {
            m_actor->moveTo(m_beforeX, m_beforeY);
        }
    private:
        int m_x, m_y;
        int m_beforeX, m_beforeY;
        Actor *m_actor;
    };
    

    MoveCommand 是ConcreteCommand,实现了Commad接口的操作
    Actor是Receiver,因为actor是实际操作的执行者

    class Invoker {
    public:
        Invoker() {
            cmdList = new stack<Command*>();
        }
        void RunCommad(Command *cmd) {
            cmdList->push(cmd);
            cmd->execute();
        }
        void UndoCommad() {
            cmdList->top()->undo();
            cmdList->pop();
        }
    private:
        stack<Command*> *cmdList;
    };
    
    class Client {
    public:
        void Play() {
        
            Actor actor;
            Invoker invoker;
            Command *c1 = new MoveCommand(&actor, 1, 1);
            invoker.RunCommad(c1);
            Command *c2 = new MoveCommand(&actor, 2, 2);
            invoker.RunCommad(c2);
            invoker.UndoCommad();
        }
    };
    

    命令模式的适用场景:

    1. 系统需要支持命令的撤销(undo),命令对象还可以提供redo方法,以供客户端在需要时,再重新实现命令效果

    2. 系统需要在不同的时间指定请求、将请求排队。一个命令对象和原先的请求发出者可以有不同的生命周期。这时命令的接受者可以在本地,也可以在网络的另一个地址。命令对象可以串行地传送到接受者上去。

    3. 如果一个系统要将系统中所有的数据消息更新到日志里,以便在系统崩溃时,可以根据日志里读回所有数据的更新命令,重新调用方法来一条一条地执行这些命令,从而恢复系统在崩溃前所做的数据更新

    4. 系统需要使用命令模式作为“CallBack(回调)”在面向对象系统中的替代。Callback即是先将一个方法注册上,然后再以后调用该方法

    命令模式的优缺点

    命令模式使得命令发出的一个和接收的一方实现低耦合,从而有以下的优点:

    • 命令模式使得新的命令很容易被加入到系统里
    • 可以设计一个命令队列来实现对请求的Undo和Redo操作
    • 可以较容易地将命令写入日志
    • 可以把命令对象聚合在一起,合成为合成命令。合成命令式合成模式的应用

    命令模式的缺点:

    • 使用命令模式可能会导致系统有过多的具体命令类。这会使得命令模式在这样的系统里变得不实际

    命令模式总结:

    1. 它能很容易的维护所有命令的集合(该命令集合的命令实际调用许多参数不一样的函数,例如moveTo(Actor *actor, int x, int y)fire(Actor *self, Actor target)

    2. 它可以很方便的实现撤销和恢复命令

    3. 可以很方便的将每个执行记录日志

    4. 最重要的就是将发起者与实现者分离(一套Actor操作的实现可以由AI和人两种发起者来发起)

    参考:http://gameprogrammingpatterns.com/command.html

    相关文章

      网友评论

          本文标题:游戏设计模式【命令模式】

          本文链接:https://www.haomeiwen.com/subject/mkpryttx.html