《游戏编程模式》各种模式汇总(三)

文章介绍了观察者模式,用于系统解耦,当底层系统触发事件时通知观察者。它维护了观察者列表,但存在同步问题。命令模式同样用于解耦,通过命令对象封装操作。事件队列则用于管理需要立即执行的命令,提供延迟、合并等控制。文章提供了相关模式的示例代码并提到了PDF资源。
摘要由CSDN通过智能技术生成
  1. 观察者模式

使用场景:

为了实现对两个系统的解耦,该模式是最有效和好用的模式。

当底层系统判断某些功能触发时,会像管线发送一条“消息”,通知他tigger触发,当上层

的某个系统注册为观察者时,它可以对该消息进行响应。即使移除了上层系统,“消息”仍然

会发送到管线,只是没人接收

优缺点:

1)被观察者维护的观察者列表,添加观察者时是动态分配内存的

解决方案:链式观察者

todo:

2)同步问题,事件队列或可解决?

3)观察者的销毁导致的空指针

解决方案:待补充

/*---------------------------------观察者模式-----------------------------

 */

// -------------------------------Demo-----------------------------//
// 观察者,消息的接收方
class Observer
{
private:
    void A_execute()
    {
        // 执行事件A的内容
    }

public:
    Observer() {}
    ~Observer() {}

    virtual void onNotify(const Enity &entity, Event event)
    {
        // 检测收到的通知类型
        switch (event)
        {
        case Event_A:
            A_execute();
            break;
            // and so on
        }
    }
};

// 被观察者,消息的发送方
class Subject
{
private:
    // 一个列表,存储需要通知的观察者
    Observer *_Observers[100];

public:
    Subject(/* args */) {}
    ~Subject() {}

    // 添加删除API
    void addObserver(Observer *observer);
    void removeObserver(Observer *observer);

protected:
    /*

    protected使得只有继承了Subject的派生类才能发送通知
    改进:更加好的解决方案是,不用这个继承,对于需要被观察的对象,可以生成一个Subject实例
    对象,用这个实例来通知观察者,但需要通知时,调用Subject.notify()就行

    */

    // 发送通知,遍历观察者列表,对其中每一个观察者发送通知
    void notify(const Enity &entity, Event event)
    {
        // 注意:此时不能在notify()方法里修改_Observers数组长度,否则会导致for循环Bug
        for (auto &&i : _Observers)
            i->onNotify(entity, event);
    }
};
  1. 命令模式

使用场景:类似于观察者模式,实现对命令的接收者和发送者的解耦。

优缺点:待补充

/*---------------------------------命令模式-----------------------------
*/

// -------------------------------Demo-----------------------------//

// 基类命令类
class Command
{
public:
    // 执行接口
    virtual void execute() = 0;
};

// 具体命令(子命令)类
class ConcreteCommand : public Command
{
private:
    /* 若要支持撤销,可以:
    1、用几个变量记录execute()会改变的变量的先前状态,在undo()中恢复状态
    2、持久化数据结构
     */
    Receiver *_receiver;

public:
    // 构造函数,实现了这个命令对象对接收者的绑定
    ConcreteCommand(Receiver *receiver) : _receiver(receiver){};
    virtual void execute() override
    {
        // 接收者执行其内部的execute()
        _receiver->execute();
    }
};

// 接收者类
class Receiver
{
public:
    // 接收者内部的执行(这是真正执行的地方,比如移动,这里的execue()应该调用unity的Move()来移动)
    void execute();
};

// 调用者(即创建命令的人)类
class Invoker
{
private:
    // 命令池,调用者需要实现的一系列命令
    Command *_commandPool[100];

public:
    // 设置命令
    void setCommand(Command *command, int index)
    {
        // 没有检测数组越界
        _commandPool[index] = command;
    }
    // 顺序执行命令池中的命令
    void invoke()
    {
        for (auto &&i : _commandPool)
            i->execute();
    };
};

// 客户端
int main(int argc, char const *argv[])
{
    // 创建接收者
    Receiver *receiver = new Receiver();
    // 创建命令对象,设定它的接收者,由接收者实现具体命令行为
    ConcreteCommand concreteCommand(receiver);
    // 创建调用者,把命令对象设置进去
    Invoker invoker;
    invoker.setCommand(&concreteCommand, 0);
    invoker.invoke();
    return 0;
}
  1. 事件队列

如果只是想要解耦接收者和发送者,应该使用命令模式和观察者模式,事件队列是用来处理需要

“立即”执行的命令是采用的,因此事件队列应该是建立在命令模式和观察者模式上的扩展。

使用场景:代码A需要代码B去执行某些操作,A应该将请求(在命令模式中是“命令”,在观察者

模式中是“消息”)推给B。同时B应该在合适的时候将请求拉取下来执行。队列在二者中构建了

一个缓存,可以实现延迟、合并、忽视这些请求,因此请求的控制权从请求者A中转移到接收者B

中。(在命令模式中,请求方A可以控制什么时候发送、是否发送、发送几条请求,接收方B只负

责收到请求后执行;在观察者模式中类似,由被观察者控制请求,观察者只能执行请求)

注意:事件队列比较复杂,需要仔细考虑是否使用

代码以后有时间再补充

/*---------------------------------事件队列-----------------------------
*/
// -------------------------------Demo-----------------------------//

这本书的pdf放在这里:

链接:https://pan.baidu.com/s/1OFDVrZcZqKSAo77HfDvuYA?pwd=7xt3

提取码:7xt3

有需要的自取

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值