让事件不受保护是坏事吗?

Is it bad to leave events unprotected?

提问人:DLWHI 提问时间:8/22/2022 更新时间:8/22/2022 访问量:52

问:

我正在编写一些代码,其中包括自定义实现的事件以及使用这些事件并在发生某些事情时调用它们的类(例如窗口关闭)。它看起来像这样:

// phony.h
class Phony
{
    public:
        Phony();
        ~Phony();
        // some stuff
        void i_invoke_click();
        void i_invoke_resize();
    private:
        Event<Arg1> click;
        Event<> resize;
        Event<Arg2> event3;
        Event<Arg3> event4;
};

// event.h
template <typename... Args>
class Event
{
    public:
        void invoke(Args... params) const
        void add(std::function<void(Args...)> func)
        void remove(std::function<void(Args...)> func)

        void operator+=(std::function<void(Args...)> func) // same as add
        void operator-=(std::function<void(Args...)> func) // same as remove
        void operator()(Args... params) // invoke

    private:
        std::list<std::function<void(Args...)>> invoke_list;
};

现在我需要实现一些接口,以便其他类可以订阅/取消订阅单击等事件。我考虑了两种方法:

  1. 使访问方法像(这将使许多方法变得不方便)subscribe_to_click(func)
  2. 或者将事件公开,以便您可以通过 +=(这很方便)直接访问它们

但我认为第二种放置事件的方式违反了封装,但我不确定。所以问题是:是否可以公开事件,或者我应该以丑陋(但安全)的方式进行?

C++ OOP 事件

评论

0赞 RoQuOTriX 8/22/2022
据我了解,客户端当前可以访问 ?客户端应该能够对此对象执行什么操作?它应该能够调用事件,例如?如果没有,则应使用事件的抽象Phony
0赞 DLWHI 8/22/2022
@RoQuOTriX 在我的特殊情况下,可以调整大小/移动/关闭/单击等窗口。用户可以通过方法手动设置一些参数(例如大小),并在窗口中绘制一些图像等内容。Phony

答:

2赞 RoQuOTriX 8/22/2022 #1

来自 C# 背景的我建议是将像 IObservable 这样的基类用于 Events,它通过运算符重载实现某种方法或方法。然后,通过返回引用事件本身的引用,使 IObservables 公开:subscribe

#include <functional>
#include <list>

template <typename... Args>
class IObservable
{
public:
    void operator+=(std::function<void(Args...)> func); // same as add
    void operator-=(std::function<void(Args...)> func); // same as remove
};

template <typename... Args>
class Event : public IObservable<Args...>
{
public:
    void operator()(Args... params); // invoke

private:
    std::list<std::function<void(Args...)>> invoke_list;
};

class Phony
{
public:
    Phony();
    ~Phony();

    void i_invoke_click();
    void i_invoke_resize();

    IObservable<int>& Click() { return click; }
    IObservable<>& Resize() { return resize; }
    IObservable<int>& Event3() { return event3; }
    IObservable<int>& Event4() { return event4; }

private:
    Event<int> click;
    Event<> resize;
    Event<int> event3;
    Event<int> event4;
};

void foo(int x);

int main()
{
    Phony p;
    p.Click() += &foo;
    // p.Click()(); no invoke possible
}

评论

0赞 DLWHI 8/22/2022
没这么想过,谢谢你的回答。