到目前为止我所拥有的是:
Observer.h
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen, SlideTransition
screen_manager = ScreenManager(transition=SlideTransition())
class RootScreen(Screen):
settings_button = Button(text='Settings')
settings_button.bind(on_press=screen_manager.switch_to(SettingsScreen())
class SettingsScreen(Screen):
pass
class WifiApp(App):
def build(self):
screen_manager.add_widget(RootScreen(name='main'))
screen_manager.add_widget(SettingsScreen(name='settings'))
return screen_manager
if __name__ == '__main__':
WifiApp().run()
Observer.cpp
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;
};
(de / constructors在这里实现但是空的,所以我把它们排除了)
我所坚持的是如何实施取消订阅程序。我遇到了擦除 - 删除 - 结尾的习语,但我明白它不起作用&#34;开箱即用&#34;我如何设置我的Observable。如何检查观察者向量中的weak_ptr元素,以便我可以删除所需的Observer?
我也在寻找关于我的Un / Subscribe程序的参数类型应该是什么的一些建议。使用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();
}
}
}
或std::shared_ptr<Observer>&
会不会更好,因为我们不会修改它?
我真的不希望Observable拥有他们的Observers,因为它似乎背叛了模式的意图,当然不是我想要构建最终将利用该模式的项目的其余部分。也就是说,我正在考虑增加一层安全/自动化,让Observers存储一个weak_ptr的镜像向量。然后,一个观察员可以取消订阅它所订阅的所有Observable,并且一个Observable可以在观察它的每个观察者身上抹去对它自己的反向引用。显然,在这种情况下,这两个班级将成为朋友。
答案 0 :(得分:3)
您可以将std::remove_if
与Object[] values
一起使用,如下所示:
std::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()
);
}
作为observer
传递。
答案 1 :(得分:2)
我坚持的是如何实施取消订阅程序。
我建议将观察者存储在std :: list中,因为它的迭代器在容器修改时不会失效。然后在obserbe中的subscribe中存储迭代器,并在取消订阅时使用迭代器来删除元素。 但是当然你可以使用另一个答案中建议的std :: vector和std :: remove_if。
现在关于所有* _ptr的东西。在C ++中,RAII是你的朋友所以使用它。摆脱公共取消订阅方法。相反,观察者必须在其析构函数中取消订阅。这简化了事情:不再锁定弱指针:如果已经删除了观察者,那么它就不在列表中。如果您有多线程应用程序,请不要忘记使用互斥锁保护观察者列表。如果你使用这个设计,那么Observable只需要指向Observers的普通指针,并且不存在必须如何存储Observers的要求。
class Observer {
public:
void subscribe(std::function<void()> unsubscribe) {
unsubscribe_ = std::move(unsubscribe);
}
virtual ~Observer() {
unsubscribe_();
}
private:
std::function<void()> unsubscribe_;
};
class Observable {
public:
void subscribe(Observer* observer) {
std::lock_guard<std::mutex> lock(observablesMutex_);
auto itr = observers_.insert(observers_.end(), observer);
observer->subscribe([this, itr]{
std::lock_guard<std::mutex> lock(observablesMutex_);
observers_.erase(itr);
});
}
private:
std::list<Observer*> observers_;
std::mutex observablesMutex_;
};
注意:对于此代码,必须始终在Observable之前销毁观察者。
更新:如果你习惯了C ++ lambdas,你可能会发现在很多情况下使用std :: function作为观察者比使用特殊的类层次结构更方便。在这种情况下,您可以使用以下API:
class Handle {
public:
explicit Handle(std::function<void()> onDestroy)
: onDestroy_(std::move(onDestroy)) {}
Handle(const Handle&) = delete;
Handle(Handle&&) = default;
virtual ~Observer() {
onDestroy_();
}
private:
std::function<void()> onDestroy_;
};
class Observable {
public:
Handle subscribe(std::function<void()> observer) {
std::lock_guard<std::mutex> lock(observablesMutex_);
auto itr = observers_.insert(observers_.end(), observer);
return {[this, itr]{
std::lock_guard<std::mutex> lock(observablesMutex_);
observers_.erase(itr);
}};
}
private:
std::list<std::function<void()>> observers_;
std::mutex observablesMutex_;
};