2

以下では、オブザーバーがさまざまなアイテムを観察したい場合に、オブザーバー パターンの sudo コードを記述しようとしました。

構文エラーは無視してください。これがこれを実装する正しい方法であるかどうかを知りたいです。そうでない場合は、より良い方法を提案してください。

// Used by the subject for keeping a track of what items the observer wants to observe
typedef struct observerListStruct
{
    bool getTemperatureUpdate;
    bool getHumidityUpdate;
    bool getPressureUpdate;
    observer's-function pointer's address;
};

// Subject's class
class weatherData
{
    public:
        // Observers will call this function to register themselves. The function pointer will point to the function which will get called when updates are available.
        void registerObservers (observer obj, observer's-FunctionPointer)
        {
            // This observer's function returns which items to observe.
            char* f = obj.returnItemsToObserve ();
            if f[0] = `1`
                observerListStruct.getTemperatureUpdate = true;
        }

        void unregisterObservers (observer obj) {}

    private:
        vector <observerListStruct> observerList;
        float temperature;
        float humidity;
        float pressure;

        void notifyObservers ()          {}

        float getTemperature ()          {}
        float getHumidity ()                 {}
        float getPressure ()                 {}
} weatherDataObject;

// Base class for observers containing common functions
class observers
{
    char ItemsToObserve [3] = {1, 2, 3};

    // This observer's function returns which items to observe. Default - return all items
        virtual char* returnItemsToObserve ()
    {
        return ItemsToObserve;
    }
};

class observerDisplayElementCurrentConditions : public observers
{
    char ItemsToObserve [3] = {1, 2};

    char* returnItemsToObserve ()
    {
        return ItemsToObserve;
    }

    // this function will be used as a function pointer for getting updates
    void getUpdatesAndDisplayWeatherData (float, float) {}
};
4

5 に答える 5

3

よりパターン指向のソリューション (ただし、関数ポインターを使用しない) は、次のようになります。WeatherObserver-Class をパラメータ化して、必要な値のみを取得できます。

#include <list>
#include <iostream>

class Observable;   //forward declaration

//Base class for all observers
class Observer {
    friend class Observable;    //allow access to observedSubject

protected:
    Observable *observedSubject;

public:
    virtual void update(){};
};


//Base class for all observables
class Observable {
private:
    std::list<Observer * const> m_registeredObservers;

public:
    ~Observable()
    {
        //delete the observers
        std::list<Observer * const>::iterator it = m_registeredObservers.begin();

        while (it != m_registeredObservers.end())
        {
            delete *it;
            it = m_registeredObservers.erase(it);
        }
    }

    void addObserver(Observer * const _pObserver)
    {
        _pObserver->observedSubject = this;
        m_registeredObservers.push_back(_pObserver);
    }

    void removeObserver(Observer * const _pObserver)
    {
        m_registeredObservers.remove(_pObserver);
        delete _pObserver;
    }

    void notifyObservers()
    {
        std::list<Observer * const>::iterator it = m_registeredObservers.begin();

        while (it != m_registeredObservers.end())
        {
            (*it)->update();
            it++;
        }
    }
};

//Concrete Observable
class WeatherData : public Observable {
private:
    float temperature;
    float humidity;
    float pressure;

public:
    WeatherData(): temperature(0), humidity(0), pressure(0)
    {};

    float getTemperature () const 
    {
        return temperature;
    }

    float getHumidity () const 
    {
        return humidity;
    }

    float getPressure () const 
    {
        return pressure;
    }

    void setTemperature(float _temperature)
    {
        if (temperature != _temperature)
        {
            temperature = _temperature;
            notifyObservers();
        }
    }

    void setHumidity(float _humidity)
    {
        if (humidity != _humidity)
        {
            humidity = _humidity;
            notifyObservers();
        }
    }

    void setPressure(float _pressure)
    {
        if (pressure != _pressure)
        {
            pressure = _pressure;
            notifyObservers();
        }
    }

};


//Concrete implementation of an weather observer
class WeatherObserver : public Observer 
{
    public:
        WeatherObserver():Observer(){};
        void update()
        {
            WeatherData* pWeatherPtr = static_cast<WeatherData*>(observedSubject);
            if (pWeatherPtr != 0)
            {
                float actHumidity = pWeatherPtr->getHumidity();
                float actPressure = pWeatherPtr->getPressure();
                float actTemperature = pWeatherPtr->getTemperature();

                //do something with the data
                std::cout << "WeatherObserver update" << std::endl;
                std::cout << "Temperature : " << actTemperature << std::endl;
                std::cout << "Humidity : " << actHumidity << std::endl;
                std::cout << "Pressure : " << actPressure << std::endl;
            }
        }
};

int main()
{
    WeatherData weatherData;
    Observer * pObserver = new WeatherObserver();
    weatherData.addObserver(pObserver);

    weatherData.setHumidity(100);
    weatherData.setTemperature(100);
}
于 2012-05-02T09:27:17.103 に答える
2
#include <algorithm>
#include <vector>


class WeatherFlags
{
public:
    WeatherFlags()
        : mask_(0)
    {}
    union {
        struct {
            unsigned int temperature_ : 1;
            unsigned int humidity_ : 1;
            unsigned int pressure_ : 1;
        };
        unsigned int mask_;
    };
};

class WeatherData;

class WeatherEvent
{
public:
    WeatherEvent(WeatherData* data, WeatherFlags const& flags)
        : data_(data)
        , flags_(flags)
    {}
    double getTemperature() const;

    WeatherData* data_;
    WeatherFlags flags_;  
};

class WeatherListener
{
public:
    virtual ~WeatherListener() = 0;
    virtual void onWeatherUpdate(WeatherEvent& e) = 0;
};
inline WeatherListener::~WeatherListener() {}

class WeatherListenerEntry
{
public:
    WeatherListenerEntry()
        : listener_(0)
    {}
    WeatherListenerEntry(WeatherListener* listener, WeatherFlags const& flags)
        : listener_(listener)
        , flags_(flags)
    {}

    WeatherListener* listener_;
    WeatherFlags flags_;
};

class WeatherData
{
public:
    WeatherData();
    void addListener(WeatherListener* listener, WeatherFlags const& flags);
    void removeListener(WeatherListener* listener);

    void notify(WeatherFlags const& flags);

    double getTemperature() const { return temperature_; }
private:
    typedef std::vector<WeatherListenerEntry> Listeners;
    Listeners listeners_;
    double temperature_;
};

WeatherData::WeatherData()
: temperature_(0)
{}

void WeatherData::addListener(WeatherListener* listener, WeatherFlags const& flags)
{
    // TODO Could maybe check for the addition of duplicates here...
    listeners_.push_back(WeatherListenerEntry(listener, flags));
}

void WeatherData::removeListener(WeatherListener* listener)
{
    struct ListenerEquals {
        WeatherListener* listener_;
        ListenerEquals(WeatherListener* listener)
            : listener_(listener)
        {}
        bool operator()(WeatherListenerEntry const& e) const {
            return (e.listener_ == listener_);
        }
    };
    listeners_.erase(
        std::remove_if(listeners_.begin(), listeners_.end(), ListenerEquals(listener)),
        listeners_.end());
}

void WeatherData::notify(WeatherFlags const& flags)
{
    WeatherEvent evt(this, flags);
    for (Listeners::iterator i = listeners_.begin(); i != listeners_.end(); ++i)
    {
        if (0 != (i->flags_.mask_ & flags.mask_)) {
            i->listener_->onWeatherUpdate(evt);
        }
    }
}

double 
WeatherEvent::getTemperature() const
{
    return data_->getTemperature();
}


#include <iostream>
class WeatherObserverStdout : public WeatherListener
{
public:
    void observe(WeatherData& data) {
        WeatherFlags flags;
        flags.temperature_ = true; // interested in temperature only.
        data.addListener(this, flags);        
    }
    virtual void onWeatherUpdate(WeatherEvent& e);
};

void
WeatherObserverStdout::onWeatherUpdate(WeatherEvent& e)
{
    double temp = e.getTemperature();
    std::cout << "Temperatrure: " << temp << std::endl;
}

int _tmain(int argc, _TCHAR* argv[])
{
    WeatherData wdata;
    WeatherObserverStdout obs;
    obs.observe(wdata);

    WeatherFlags flags;
    wdata.notify(flags);
    flags.temperature_ = true;
    wdata.notify(flags);
    return 0;
}
于 2012-05-02T09:22:02.347 に答える
1

私の2セント...

Observer パターンのクラシック (Gang of Four) 実装は、サブジェクトのプロパティの変更をオブザーバーに通知します。あなたの質問では、オブザーバーをサブジェクト全体ではなく、特定のプロパティに登録したいと考えています。オブザーバー パターンを 1 レベル下に移動し、プロパティを具体的なサブジェクトとして取り、それらのオブザーバーを (プロパティごとに) 定義することができますが、この問題を解決するためのより良い方法が 1 つあります。

C# では、Observer パターンはeventsdelegatesによって実装されます。デリゲートは、イベント ハンドラー (イベントが発生したときに実行する必要がある関数) を表します。デリゲートは、イベントに追加 (登録) または削除 (登録解除) することができます。

C++ では、ファンクターはデリゲートとして機能します。異なるコンテキストでグローバル関数またはクラス メソッドを呼び出すために必要なすべての情報を格納できます。イベントは(登録された)ファンクターのコレクションであり、イベントが発生する(呼び出される)と、基本的にそのリストを通過し、すべてのファンクターを呼び出します(Publisher::publishjuanchopanzaのソリューションのメソッドを参照)。

イベントとデリゲートのC++バージョンを実装し、それらをあなたのケースに適用できる修正されたオブザーバーパターンで使用しようとしました。これは私が思いついたものです:

#include <list>
#include <iostream>
#include <algorithm>

// use base class to resolve the problem of how to put into collection objects of different types
template <typename TPropertyType>
struct PropertyChangedDelegateBase
{
    virtual ~PropertyChangedDelegateBase(){};
    virtual void operator()(const TPropertyType& t) = 0;
};

template <typename THandlerOwner, typename TPropertyType>
struct PropertyChangedDelegate : public PropertyChangedDelegateBase<TPropertyType>
{
    THandlerOwner* pHandlerOwner_;

    typedef void (THandlerOwner::*TPropertyChangeHandler)(const TPropertyType&);
    TPropertyChangeHandler handler_;

public:
    PropertyChangedDelegate(THandlerOwner* pHandlerOwner, TPropertyChangeHandler handler) : 
      pHandlerOwner_(pHandlerOwner), handler_(handler){}

    void operator()(const TPropertyType& t)
    {
        (pHandlerOwner_->*handler_)(t);
    }
};

template<typename TPropertyType>
class PropertyChangedEvent
{
public:
    virtual ~PropertyChangedEvent(){};

    void add(PropertyChangedDelegateBase<TPropertyType>* const d)
    {
        std::list<PropertyChangedDelegateBase<TPropertyType>* const>::const_iterator it = std::find(observers_.begin(), observers_.end(), d);
        if(it != observers_.end())
            throw std::runtime_error("Observer already registered");

        observers_.push_back(d);
    }


    void remove(PropertyChangedDelegateBase<TPropertyType>* const d)
    {       
        std::list<PropertyChangedDelegateBase<TPropertyType>* const>::const_iterator it = std::find(observers_.begin(), observers_.end(), d);
        if(it != observers_.end())
            observers_.remove(d);
    }   

    // notify
    void operator()(const TPropertyType& newValue)
    {
        std::list<PropertyChangedDelegateBase<TPropertyType>* const>::const_iterator it = observers_.begin();
        for(; it != observers_.end(); ++it)
        {
            (*it)->operator()(newValue);
        }
    }

protected:
    std::list<PropertyChangedDelegateBase<TPropertyType>* const> observers_;
};

// class that owns concrete subjects
class PropertyOwner1
{
    int property1_;
    float property2_;   
public:
    PropertyChangedEvent<int> property1ChangedEvent;
    PropertyChangedEvent<float> property2ChangedEvent;

    PropertyOwner1() : 
        property1_(0), 
        property2_(0.0f)
    {}  

    int property1() const {return property1_;}
    void property1(int n) 
    {
        if(property1_ != n)
        {
            property1_ = n;
            std::cout << "PropertyOwner1::property1(): property1_ set to " << property1_ << std::endl;
            property1ChangedEvent(property1_);
        }
    }

    float property2() const {return property2_;}
    void property2(float n) 
    {
        if(property2_ != n)
        {
            property2_ = n;
            std::cout << "PropertyOwner1::property2(): property2_ set to " << property2_ << std::endl;
            property2ChangedEvent(property2_);
        }
    }
};

// class that owns concrete subjects
class PropertyOwner2
{
    bool property1_;
    double property2_;  
public:
    PropertyChangedEvent<bool> property1ChangedEvent;
    PropertyChangedEvent<double> property2ChangedEvent;

    PropertyOwner2() : 
        property1_(false), 
        property2_(0.0)
    {}  

    bool property1() const {return property1_;}
    void property1(bool n) 
    {
        if(property1_ != n)
        {
            property1_ = n;
            std::cout << "PropertyOwner2::property1(): property1_ set to " << property1_ << std::endl;
            property1ChangedEvent(property1_);
        }
    }

    double property2() const {return property2_;}
    void property2(double n) 
    {
        if(property2_ != n)
        {
            property2_ = n;
            std::cout << "PropertyOwner2::property2(): property2_ set to " << property2_ << std::endl;
            property2ChangedEvent(property2_);
        }
    }
};

// class that observes changes in property1 of PropertyOwner1 and property1 of PropertyOwner2
struct PropertyObserver1
{   
    void OnPropertyOwner1Property1Changed(const int& newValue)
    {
        std::cout << "\tPropertyObserver1::OnPropertyOwner1Property1Changed(): \n\tnew value is: " << newValue << std::endl;
    }

    void OnPropertyOwner2Property1Changed(const bool& newValue)
    {
        std::cout << "\tPropertyObserver1::OnPropertyOwner2Property1Changed(): \n\tnew value is: " << newValue << std::endl;
    }
};

// class that observes changes in property2 of PropertyOwner1 and property2 of PropertyOwner2
struct PropertyObserver2
{   
    void OnPropertyOwner1Property2Changed(const float& newValue)
    {
        std::cout << "\tPropertyObserver2::OnPropertyOwner1Property2Changed(): \n\tnew value is: " << newValue << std::endl;
    }

    void OnPropertyOwner2Property2Changed(const double& newValue)
    {
        std::cout << "\tPropertyObserver2::OnPropertyOwner2Property2Changed(): \n\tnew value is: " << newValue << std::endl;
    }
};

int main(int argc, char** argv)
{
    PropertyOwner1 propertyOwner1;  
    PropertyOwner2 propertyOwner2;      

    PropertyObserver1 propertyObserver1;
    PropertyObserver2 propertyObserver2;

    // register observers
    PropertyChangedDelegate<PropertyObserver1, int> delegate1(&propertyObserver1, &PropertyObserver1::OnPropertyOwner1Property1Changed);
    propertyOwner1.property1ChangedEvent.add(&delegate1);

    PropertyChangedDelegate<PropertyObserver2, float> delegate2(&propertyObserver2, &PropertyObserver2::OnPropertyOwner1Property2Changed);
    propertyOwner1.property2ChangedEvent.add(&delegate2);

    PropertyChangedDelegate<PropertyObserver1, bool> delegate3(&propertyObserver1, &PropertyObserver1::OnPropertyOwner2Property1Changed);
    propertyOwner2.property1ChangedEvent.add(&delegate3);

    PropertyChangedDelegate<PropertyObserver2, double> delegate4(&propertyObserver2, &PropertyObserver2::OnPropertyOwner2Property2Changed);
    propertyOwner2.property2ChangedEvent.add(&delegate4);

    propertyOwner1.property1(1);
    propertyOwner1.property2(1.2f);

    propertyOwner2.property1(true);
    propertyOwner2.property2(3.4);

    // unregister PropertyObserver1
    propertyOwner1.property1ChangedEvent.remove(&delegate1);
    propertyOwner2.property1ChangedEvent.remove(&delegate3);

    propertyOwner1.property1(2);
    propertyOwner1.property2(4.5f);
}

出力:

    PropertyOwner1::property1(): property1_ set to 1
      PropertyObserver1::OnPropertyOwner1Property1Changed():
      new value is: 1 
    PropertyOwner1::property2(): property2_ set to 1.2
      PropertyObserver2::OnPropertyOwner1Property2Changed():
      new value is: 1.2 
    PropertyOwner2::property1(): property1_ set to 1
      PropertyObserver1::OnPropertyOwner2Property1Changed():
      new value is: 1 
    PropertyOwner2::property2(): property2_ set to 3.4
      PropertyObserver2::OnPropertyOwner2Property2Changed():
      new value is: 3.4 
    PropertyOwner1::property1(): property1_ set to 2 
    PropertyOwner1::property2(): property2_ set to 4.5
      PropertyObserver2::OnPropertyOwner1Property2Changed():
      new value is: 4.5

各オブザーバーは特定のプロパティに登録され、通知されると、各オブザーバーはプロパティの所有者とプロパティの新しい値を正確に認識します。

于 2012-05-03T15:58:37.200 に答える