開發中常常有一個需求就是當某個對象甚至是某個模塊的屬性變化,或者是某個操做發生的時候須要設置一個監聽器以通知出去,自己就是實現一個最簡單夠用的機制.函數
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); }