c++ PropertyChangeListener的實現

前言

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

 

代碼

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);
}
相關文章
相關標籤/搜索