使用weak_ptr实现Observer模式

oph*_*coe 7 c++ observers weak-ptr observer-pattern c++11

到目前为止我所拥有的是:

Observer.h

class Observer
{
public:
    ~Observer();
    virtual void Notify() = 0;
protected:
    Observer();
};

class Observable
{
public:
    ~Observable();
    void Subscribe( std::shared_ptr<Observer> observer );
    void Unsubscribe( std::shared_ptr<Observer> observer );
    void Notify();
protected:
    Observable();
private:
    std::vector<std::weak_ptr<Observer>> observers;
};
Run Code Online (Sandbox Code Playgroud)

Observer.cpp

void Observable::Subscribe( std::shared_ptr<Observer> observer )
{
    observers.push_back( observer );
}

void Observable::Unsubscribe( std::shared_ptr<Observer> observer )
{
    ???
}

void Observable::Notify()
{
    for ( auto wptr : observers )
    {
        if ( !wptr.expired() )
        {
            auto observer = wptr.lock();
            observer->Notify();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

(de/constructors在这里实现但是空的,所以我把它们排除了)

我坚持的是如何实施Unsubscribe程序.我遇到了擦除 - 删除 - 结尾的习语,但我知道它不会像我设置我的Observable那样"开箱即用".如何检查观察者向量中的weak_ptr元素,以便我可以删除所需的Observer?

我也在寻找关于我的Un/Subscribe程序的参数类型应该是什么的一些建议.使用std::shared_ptr<Observer>&或更好const std::shared_ptr<Observer>&,因为我们不会修改它?

我真的不希望Observable拥有他们的Observers,因为它似乎背叛了模式的意图,当然不是我想要构建最终将利用该模式的项目的其余部分.也就是说,我正在考虑增加一层安全/自动化,让Observers存储一个weak_ptr的镜像向量.然后,一个出口观察者可以取消订阅它所订阅的所有Observable,并且一个Observable在其出路时可以从观察它的每个观察者中删除对它自己的反向引用.显然,在这种情况下,这两个班级将成为朋友.

was*_*ful 4

您可以std::remove_ifstd::erase这样使用:

void Observable::Unsubscribe( std::shared_ptr<Observer> observer )
{
    std::erase(
        std::remove_if(
            this->observers.begin(),
            this->observers.end(),
            [&](const std::weak_ptr<Observer>& wptr)
            {
                return wptr.expired() || wptr.lock() == observer;
            }
        ),
        this->observers.end()
    );
}
Run Code Online (Sandbox Code Playgroud)

您确实应该传递observerconst std::shared_ptr<Observer>&.

  • 请注意,“std::remove_if”不会从容器中删除元素。您必须同时使用“container.erase”。搜索擦除删除习语。 (3认同)