首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >事件调度系统

事件调度系统
EN

Code Review用户
提问于 2021-12-11 15:18:50
回答 1查看 639关注 0票数 3

下面您可以看到我的简单事件分派器的实现。我想得到一些有关设计的反馈或改进建议,也许还有一个如何摆脱static_cast的想法。非常感谢。

Event.h

代码语言:javascript
复制
#pragma once

#include <cstdint>

enum class EventType : uint8_t {
    ButtonPress,
    FactoryReset
};

class Event {
    public:
        Event() = default;
        explicit Event(EventType type) : mType(type) {}
        virtual ~Event() = default;

        inline const EventType Type() const { return this->mType; };

    protected:
        EventType mType;
};

ButtonPressEvent.h

代码语言:javascript
复制
#pragma once

#include "Event.h"

class ButtonPressEvent final : public Event {
    public:
        ButtonPressEvent(uint8_t pin) : Event(EventType::ButtonPress), mPin(pin) {};

        uint8_t mPin;
};

FactoryResetEvent.h

代码语言:javascript
复制
#pragma once

#include "Event.h"

class FactoryResetEvent final : public Event {
    public:
        FactoryResetEvent() : Event(EventType::FactoryReset) {};
};

Subscriber.h

代码语言:javascript
复制
#pragma once

#include <functional>
#include <map>
#include <memory>

#include "Event.h"

using EventHandlerType = std::function<void(std::unique_ptr<Event>&)>;

class Subscriber {
    public:
        virtual ~Subscriber() = default;
        virtual std::map<EventType, EventHandlerType> GetSubscribedEvents() = 0; 
};

Dispatcher.h

代码语言:javascript
复制
#pragma once

#include <map>
#include <memory>
#include <vector>

#include "Event.h"
#include "Subscriber.h"

class Dispatcher {
    public:
        Dispatcher();

        void Listen(EventType type, const EventHandlerType &funct);
        void Subscribe(Subscriber *subscriber);
        void Post(std::unique_ptr<Event> &ptr);
        void Process();

    private:
        std::map<EventType, std::vector<EventHandlerType>> mObservers;
        std::vector<std::unique_ptr<Event>> mEvents;
};

Dispatcher.cpp

代码语言:javascript
复制
#include "Dispatcher.h"

void Dispatcher::Listen(EventType type, const EventHandlerType &funct) {
    this->mObservers[type].push_back(funct);
}

void Dispatcher::Subscribe(Subscriber *subscriber) {
    for (auto&& event : subscriber->GetSubscribedEvents()) {
        this->Listen(event.first, event.second);
    }
}

void Dispatcher::Post(std::unique_ptr<Event> &ptr) {
    this->mEvents.push_back(std::move(ptr));
}

void Dispatcher::Process() {
    if (this->mEvents.empty()) {
        return;
    }

    for (auto&& event : this->mEvents) {
        // call listener functions
        for (auto&& observer : this->mObservers.at(event->Type())) {
            observer(event);
        }
    }

    this->mEvents.clear();
}

使用

App.h

代码语言:javascript
复制
#pragma once

#include "Subscriber.h"

class App : public Subscriber {
    public:
        std::map<EventType, EventHandlerType> GetSubscribedEvents();
        void OnButtonPressEvent(std::unique_ptr<Event> &event);
};

App.cpp

代码语言:javascript
复制
#include <functional>
#include <stdio.h>

#include "App.h"
#include "Event.h"
#include "ButtonPressEvent.h"

std::map<EventType, EventHandlerType> App::GetSubscribedEvents() {
    return {
        { EventType::ButtonPress, std::bind(&App::OnButtonPressEvent, this, std::placeholders::_1) }
    };
}

void App::OnButtonPressEvent(std::unique_ptr<Event> &event) {
    ButtonPressEvent *b = static_cast<ButtonPressEvent*>(event.get());

    printf("Button pin %d pressed", b->mPin);
}

main.cpp

代码语言:javascript
复制
#include "Dispatcher.h"
#include "ButtonPressEvent.h"
#include "App.h"

void main(void) {
    App app;
    Dispatcher dispatcher;

    dispatcher.Subscribe(&app);

    // simulate event
    std::unique_ptr<Event> ptr(new ButtonPressEvent(11));
    dispatcher.Post(ptr);

    while (true) {
        dispatcher.Process();
    }
}
EN

回答 1

Code Review用户

发布于 2021-12-11 20:09:09

与编码一致,目前使用的创建默认构造函数的策略不同。

更喜欢在cpp源文件

中包含头文件

通过在头文件中包含头文件,代码可能会成为维护问题,并且在预处理器运行后编译的代码的大小可能不必要地膨胀。维护代码的人在修改C++源文件时可能不会查看头文件。这还可能减少头文件更改时需要编译的文件数。

这个对象

通常,在C++中,不需要使用this对象来指向成员变量或方法。只需使用名称即可访问成员。在Dispatcer.cpp中,不需要使用this。在您使用的编译器中,它可能是必要的,因为构造函数没有定义。在头文件FactorResetEvent.h中,构造函数也可以是默认构造函数。

代码语言:javascript
复制
#include "Dispatcher.h"

void Dispatcher::Listen(EventType type, const EventHandlerType& funct) {
    mObservers[type].push_back(funct);
}

void Dispatcher::Subscribe(Subscriber* subscriber) {
    for (auto&& event : subscriber->GetSubscribedEvents()) {
        Listen(event.first, event.second);
    }
}

void Dispatcher::Post(std::unique_ptr<Event>& ptr) {
    mEvents.push_back(std::move(ptr));
}

void Dispatcher::Process() {
    if (mEvents.empty()) {
        return;
    }

    for (auto&& event : mEvents) {
        // call listener functions
        for (auto&& observer : this->mObservers.at(event->Type())) {
            observer(event);
        }
    }

    mEvents.clear();
}

默认构造函数

如果不为对象(如Dispatcher )创建构造函数,则可以将构造函数定义为默认构造函数。在Subscriber.h中使用默认析构函数,但根本没有定义构造函数。

代码语言:javascript
复制
class Dispatcher {
public:
    Dispatcher() = default;

    void Listen(EventType type, const EventHandlerType& funct);
    void Subscribe(Subscriber* subscriber);
    void Post(std::unique_ptr<Event>& ptr);
    void Process();

private:
    std::map<EventType, std::vector<EventHandlerType>> mObservers;
    std::vector<std::unique_ptr<Event>> mEvents;
};

我的编译器和链接器(Visual 2019)报告说,当我编译程序时,构造函数是未定义的。

票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/270907

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档