关于观察者模式的问题。观察者需要来自两个或多个来源的信息怎么样

问题描述 投票:0回答:1

我刚刚仔细研究了观察者模式。我编写了一个演示片段以更好地理解它。 但是在我刚刚完成演示后,出现了一个问题,观察者模式是在一个可观察对象和多个观察者之间。观察者需要来自两个或多个来源的信息怎么样?

这里是用C++编写的演示代码,让您更好地理解我的问题(请注意下面代码片段中我的评论):

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

class IObserver;

class IObservable
{
public:
    virtual void add(IObserver*) = 0;
    virtual void remove(IObserver*) = 0;
    virtual void trigger() = 0;
    virtual double get_temperature() = 0;
    virtual ~IObservable() = default;
};

class IObserver
{
public:
    IObserver(IObservable& observable):m_observable(observable){}
    virtual void update() = 0;
    virtual ~IObserver() = default;
protected:
    IObservable& m_observable;
};

class IDisplay
{
public:
    virtual void display() = 0;
    virtual ~IDisplay() = default;
};

class WeatherStation : public IObservable
{
public:
    void add(IObserver* observer_ptr) override
    {
        if(std::find(m_observer_list.begin(), m_observer_list.end(), observer_ptr) == m_observer_list.end())
        {
            m_observer_list.push_back(observer_ptr);
        }
    }

    void remove(IObserver* observer_ptr) override
    {
        m_observer_list.erase(std::remove(m_observer_list.begin(), m_observer_list.end(), observer_ptr), m_observer_list.end());
    }
    
    void trigger()
    {
        for(const auto& observer:m_observer_list)
        {
            observer->update();
        }
    }

    double get_temperature()
    {
        return m_temperature;
    }

    void set_temperature(double temperature)
    {
        m_temperature = temperature;
        trigger();
    }

    virtual ~WeatherStation() = default;
private:
    std::list<IObserver*> m_observer_list;
    double m_temperature;
};

class CommonDisplay:public IObserver, public IDisplay
{
public:
    CommonDisplay(IObservable& observable):IObserver(observable){}

    virtual ~CommonDisplay() = default;

    void update() override
    {
        display();
    }

};

class PhoneDisplay:public CommonDisplay
{
public:
    PhoneDisplay(IObservable& observable, const std::string& name): m_name(name),CommonDisplay(observable){}

    void display() override
    {
        std::cout << m_name << "'s phone displayed, temperature: " << m_observable.get_temperature() << std::endl;
    }
private:
    std::string m_name = "unknown";
};


class WindowDisplay:public CommonDisplay
{
public:
    WindowDisplay(IObservable& observable):CommonDisplay(observable){}

    void display() override
    {
        std::cout << "WindowDisplay displayed, temperature: " << m_observable.get_temperature() << std::endl;
    }
};



int main()
{
    WeatherStation station_of_NewYork;
    WeatherStation station_of_Seattle;

    PhoneDisplay jone_phone(station_of_NewYork, "Jhone");
    PhoneDisplay lucy_phone(station_of_NewYork, "Lucy");
    station_of_NewYork.add(&jone_phone);
    station_of_NewYork.add(&lucy_phone);

    //If Lucy also what's to know the temperature of Seattle, how to achieve that goal?

    WindowDisplay bedroom_display(station_of_NewYork);
    station_of_NewYork.add(&bedroom_display);

    station_of_NewYork.set_temperature(15.6);
}
c++ c++11 design-patterns observer-pattern
1个回答
0
投票

我们可以通过订阅 observables 的

std::vector
来实现它(抱歉,我无法抗拒进行一些重构)。 这里是 godbolt 链接,如果您需要的话:

#include<iostream>
#include<string>
#include<vector>
#include<set>
#include<sstream>
#include<memory>

class IObserver;

class IObservable
{
public:
    /// @return true if added
    virtual bool add(const std::shared_ptr<IObserver>&) = 0;
    virtual void remove(const std::shared_ptr<IObserver>&) = 0;
    virtual void trigger() = 0;
    virtual double get_temperature() const = 0;
    virtual ~IObservable() = default;
};

class IObserver
{
public:
    virtual void update() = 0;
    virtual ~IObserver() = default;
};

class IDisplay
{
public:
    virtual void display() = 0;
    virtual ~IDisplay() = default;
};

class BasicObserver : public IObserver
{
public:
    using observables_container_t = std::vector<std::shared_ptr<IObservable>>;

    template<typename IterT>
    BasicObserver(IterT begin, IterT end) 
      : m_observables(begin, end)
    {}

    BasicObserver(const std::shared_ptr<IObservable>& obs)
    {
        m_observables.push_back(obs);
    }

    ~BasicObserver() override = default;
    
protected:
    observables_container_t m_observables;
};

class WeatherStation : public IObservable
{
public:
    ~WeatherStation() override = default;

    bool add(const std::shared_ptr<IObserver>& observer) override
    {
      auto emplacement_info = m_observers.emplace(observer);
      return emplacement_info.second;
    }

    void remove(const std::shared_ptr<IObserver>& observer) override
    {
        m_observers.erase(observer);
    }
    
    void trigger() override
    {
        for(const auto& observer:m_observers)
        {
            observer->update();
        }
    }

    double get_temperature() const override
    {
        return m_temperature;
    }

    void set_temperature(double temperature)
    {
        m_temperature = temperature;
        trigger();
    }
private:
    std::set<std::shared_ptr<IObserver>> m_observers;
    double m_temperature{0};
};

class CommonDisplay:public BasicObserver, public IDisplay
{
public:
    // using ctors from BasicObserver
    using BasicObserver::BasicObserver;

    ~CommonDisplay() override = default;

    void update() override
    {
        display();
    }
};

class NamedDisplay :public CommonDisplay
{
private:
    // using ctors from CommonDisplay
    using CommonDisplay::CommonDisplay;
public:
    ~NamedDisplay() override = default;

    template<typename ...CommonDisplayArgsT>
    static std::shared_ptr<NamedDisplay> make(std::string name, CommonDisplayArgsT&&... args)
    {
      auto display = std::make_shared<NamedDisplay>(std::forward<CommonDisplayArgsT>(args)...);
      display->m_name = name;
      return display;
    }

    void display() override
    {
      std::stringstream tempratures_info;
      for (const auto& obs : m_observables)
      {
          tempratures_info <<  ", temperature: " << obs->get_temperature();
      }
      std::cout << m_name << " displayed" << tempratures_info.str() << std::endl;
    }
private:
    std::string m_name;
};

int main()
{
    auto station_of_NewYork = std::make_shared<WeatherStation>();
    auto station_of_Seattle = std::make_shared<WeatherStation>();

    std::vector<std::shared_ptr<WeatherStation>> lucy_stations {
      station_of_NewYork, 
      station_of_Seattle
    };

    auto jone_phone = NamedDisplay::make("Jhone's phone", station_of_NewYork);
    auto lucy_phone = NamedDisplay::make("Lucy's phone", lucy_stations.begin(), lucy_stations.end());

    station_of_NewYork->add(jone_phone);
    for(const auto& station: lucy_stations)
    {
        station->add(lucy_phone);
    }

    auto bedroom_display = NamedDisplay::make("WindowDisplay", station_of_NewYork);
    station_of_NewYork->add(bedroom_display);

    std::cout << "Updating NewYork temprature to " << 15.6 << " ..." << std::endl;
    station_of_NewYork->set_temperature(15.6);

    std::cout << "\nUpdating Seattle temprature to " << 11.1 << " ..." << std::endl;
    station_of_Seattle->set_temperature(11.1);
}
© www.soinside.com 2019 - 2024. All rights reserved.