开发中常常有一个需求就是当某个对象甚至是某个模块的属性变化,或者是某个操做发生的时候须要设置一个监听器以通知出去,自己就是实现一个最简单够用的机制.函数
PropertyChangeSupport.h测试
#pragma once #include <boost/function.hpp> #include <boost/any.hpp> #include <vector> #include <map> typedef boost::function<void(std::string, boost::any, boost::any)> PropertyChangeListener; class PropertyChangeSupport { public: PropertyChangeSupport(); ~PropertyChangeSupport(); void addPropertyChangeListener(std::string name, PropertyChangeListener propertyChangeListener); void addPropertyChangeListener(PropertyChangeListener propertyChangeListener); virtual void firePropertyChange(std::string name, boost::any oldValue = nullptr, boost::any newValue = nullptr); private: std::map<std::string, std::vector<PropertyChangeListener>> _pairListeners; std::vector<PropertyChangeListener> _listeners; };
PropertyChangeSupport.cppspa
PropertyChangeSupport::PropertyChangeSupport() { } PropertyChangeSupport::~PropertyChangeSupport() { } void PropertyChangeSupport::addPropertyChangeListener(std::string name, PropertyChangeListener propertyChangeListener) { auto pair = _pairListeners.find(name); if (pair != _pairListeners.end()) { pair->second.push_back(propertyChangeListener); } else { _pairListeners.insert({name, {propertyChangeListener}}); } } void PropertyChangeSupport::addPropertyChangeListener(PropertyChangeListener propertyChangeListener) { _listeners.push_back(propertyChangeListener); } void PropertyChangeSupport::firePropertyChange(std::string name, boost::any oldValue, boost::any newValue) { for (int i = 0; i < _listeners.size(); ++i) { _listeners[i](name, oldValue, newValue); } auto pair = _pairListeners.find(name); if (pair != _pairListeners.end()) { auto v = pair->second; for (int i = 0; i < v.size(); ++i) { v[i](name, oldValue, newValue); } } }
实现原理很是简单,设置一个回调函数,根据不一样的propertyname调用对应的函数对象,使用boost::any来作值的包装.因为监听的方法是在同一个线程执行,因此若是监听方法代码不当就会致使失败.线程
class Bean : public PropertyChangeSupport { public: Bean() { } void setA(int v) { auto old = a; a = v; firePropertyChange("a", old, v); } void setB(std::string v) { auto old = b; b = v; firePropertyChange("b", old, b); } int a; std::string b; }; int main() { Bean b; b.addPropertyChangeListener("b", [](std::string name, boost::any oldV, boost::any newV) { LOG_INFO << name << boost::any_cast<std::string>(oldV) << boost::any_cast<std::string>(newV); }); b.addPropertyChangeListener("a", [](std::string name, boost::any oldV, boost::any newV) { LOG_INFO << name << boost::any_cast<int>(oldV) << boost::any_cast<int>(newV); }); b.addPropertyChangeListener([](std::string name, boost::any oldV, boost::any newV) { LOG_INFO << name; }); b.setB("sss"); b.setA(111); b.setA(222); }