C++ 观察者模式 - 坚持"Program to Interfaces"原则

C++ Observer Patterns - Sticking to "Program to Interfaces" principal

本文关键字:to Interfaces 原则 Program C++ 坚持 观察者模式      更新时间:2023-10-16

我正在c++中实现Head First Design Patterns中的Observer Pattern,并且我面临一个小问题。我得到了错误:"类主题没有名为setnewmeasurements的成员"行station->setNewMeasurments(0.5,10.0, 7.5);似乎如果我想使用多态性,应该在接口("Subject")中定义方法"setNewMeasurments"。但是这违背了"面向接口编程"的原则,而且我确实需要多态才能使观察者模式在这里工作。有什么意见吗?谢谢你! !

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
/**************************************************
***************    Interfaces    ******************
***************************************************/
class Observer
{
    public:
        virtual void update(float temp, float humidity, float pressure) = 0 ;
};
class Subject
{
    protected:
        vector<Observer*> observers; //est-ce une bonne idée ici?  c'est contraire au pattern strategy (separate changing elements from constant ones) -> Visiblement c'est ce qui est fait dans l'UML page 56
    public:
        virtual void registerObserver(Observer* o) = 0;
        virtual void removeObserver(Observer* o)  = 0;
        virtual void notifyObserver() = 0;
};
class DisplayElement
{
    public:
        virtual void display() const = 0 ;
};
/**************************************************
*************    Implementations    ***************
***************************************************/
class WeatherData : public Subject
{
    private:
        float temperature;
        float humidity;
        float pressure;
    public:
        virtual void registerObserver(Observer* o){
            observers.push_back(o); //y'a as un probleme la?
        }
        virtual void removeObserver(Observer* o){
            std::vector<Observer*>::iterator position=std::find(observers.begin(), observers.end(), o);
            if (position != observers.end()) 
                observers.erase(position);
            }
        virtual void notifyObserver()
        {
            for (vector<Observer*>::iterator it=observers.begin() ; it!=observers.end() ; it++)
            {
                (*it)->update(temperature, humidity, pressure);
            }
        }
        void measurmentChanged() {
            notifyObserver();
        }
        void setNewMeasurments(float temp, float hum, float press)
        {
            this->temperature=temp;
            this->humidity=hum;
            this->pressure=press;
            measurmentChanged();
        }       
};
class CurrentConditionsDisplay : public Observer, public DisplayElement
{
    private:
        float temperature;
        float humidity;
        float pressure;
        Subject* weatherData;
        // Faut penser à désallouer cette mémoire dans le destructeur --> exercice!! (le faire à la main puis utiliser le Wrapper)
    public:
        CurrentConditionsDisplay(Subject* w){
            weatherData=w;
            weatherData->registerObserver(this);
        }   
        void update(float temp, float hum, float press){
            temperature=temp;
            humidity=hum;
            pressure=press;
            display();
        }
        void display() const {
            cout << "Current Conditions Displayers  " << endl << endl;
            cout << "Temperature : " << temperature << endl;
            cout << "Humidity : " << temperature << endl;
            cout << "Pressure : " << temperature << endl;
        };
};
int main()
{
    Subject* station=new WeatherData;
    CurrentConditionsDisplay mDisp(station);
    station->setNewMeasurments(0.5,10.0, 7.5);
    delete station;
    system("PAUSE");
    return 0;
}

这里的问题是,当你写:

 Subject* station=new WeatherData;

你告诉编译器station是一个Subject,而Subject没有定义一个叫做setNewMeasurments的函数。

必须将指针station转换为WeatherData:

((WeatherData*)station)->setNewMeasurments(0.5,10.0, 7.5);

或在真正的c++中如CoffeeandCode所指出的:

static_cast<WeatherData*>(station)->setNewMeasurments(0.5,10.0, 7.5);

但是,由于WeatherDate继承自Subject,您可以直接写:

WeatherData* station=new WeatherData;
CurrentConditionsDisplay mDisp(station);
station->setNewMeasurments(0.5,10.0, 7.5);

这就是多态的工作方式!如果你声明一个对象为Subject,你只能访问Subject的函数和它的基类函数。

如果需要调用函数setNewMeasurments,则需要通过将变量station声明为WeatherData来使其可访问。

我认为你实际上想要完成的是隐藏WeatherData实现,而不是整个类。您可以通过将函数实现移动到*.cpp文件中来实现这一点。因此,在*.h文件中只有函数定义,而在*.cpp文件中只有实际代码。