我刚刚仔细研究了观察者模式。我编写了一个演示片段以更好地理解它。 但是在我刚刚完成演示后,出现了一个问题,观察者模式是在一个可观察对象和多个观察者之间。观察者需要来自两个或多个来源的信息怎么样?
这里是用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);
}
我们可以通过订阅 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);
}