《Head First 設計模式》例子的C++實現(2 觀察者模式)
阿新 • • 發佈:2019-02-11
最近在學習設計模式,用的是 《Head First 設計模式》這本書。感覺這本書寫的還是很不錯的,深入淺出的介紹了各種常用的設計模式。唯一有點不方便的地方是這本書的例子全都是用的 Java 來實現的。而我主要是用 C++。所以就動手將書上的程式碼用 C++ 來實現了一遍。
觀察者模式
首先是三個介面的程式碼:
//observer.h
#ifndef OBSERVER_H
#define OBSERVER_H
class Observer
{
public:
Observer() {}
virtual void update(double temp, double humidity, double pressure) = 0;
};
#endif // OBSERVER_H
//Subject.h
#ifndef SUBJECT_H
#define SUBJECT_H
#include "observer.h"
#include <QList>
class Subject
{
public:
Subject();
void registerObserver(Observer *o);
void removeObserver(Observer *o);
void notifyObservers();
private :
QList<Observer *> m_list;
protected:
double m_temp;
double m_humidity;
double m_pressure;
};
#endif // SUBJECT_H
#include "subject.h"
Subject::Subject()
{
}
void Subject::registerObserver(Observer *o)
{
m_list.append(o);
}
void Subject::removeObserver(Observer *o)
{
int i = m_list.indexOf(o);
if( i >= 0 )
{
m_list.removeAt(i);
}
}
void Subject::notifyObservers()
{
foreach (Observer * o, m_list)
{
o->update(m_temp, m_humidity, m_pressure);
}
}
#ifndef DISPLAYELEMENT_H
#define DISPLAYELEMENT_H
class DisplayElement
{
public:
DisplayElement() {}
virtual void display() = 0;
};
#endif // DISPLAYELEMENT_H
下面是 WeatherData 類:
#ifndef WEATHERDATA_H
#define WEATHERDATA_H
#include "subject.h"
class WeatherData : public Subject
{
public:
WeatherData();
void setMeasurements(double t, double h, double p);
void measurementsChanged();
};
#endif // WEATHERDATA_H
#include "weatherdata.h"
WeatherData::WeatherData()
{
}
void WeatherData::setMeasurements(double t, double h, double p)
{
m_temp = t;
m_humidity = h;
m_pressure = p;
measurementsChanged();
}
void WeatherData::measurementsChanged()
{
notifyObservers();
}
最後是四種觀察者:
#include "observer.h"
#include "displayelement.h"
class CurrentConditionDisplay : public Observer, public DisplayElement
{
public:
CurrentConditionDisplay();
void display() override;
void update(double temp, double humidity, double pressure) override;
private:
double m_temp;
double m_humidity;
double m_pressure;
};
class ForecastDisplay: public Observer, public DisplayElement
{
public:
ForecastDisplay();
void display() override;
void update(double temp, double humidity, double pressure) override;
private:
double currentPressure = 29.92f;
double lastPressure;
};
class HeatIndexDisplay : public Observer, public DisplayElement
{
public:
HeatIndexDisplay();
void display() override;
void update(double temp, double humidity, double pressure) override;
private:
double m_heatIndex;
double computeHeatIndex(double t, double rh);
};
class StatisticsDisplay: public Observer, public DisplayElement
{
public:
StatisticsDisplay();
void display() override;
void update(double temp, double humidity, double pressure) override;
private:
int m_numReadings;
double m_tempSum;
double m_maxTemp;
double m_minTemp;
};
#include "display.h"
#include <iostream>
using std::cout;
using std::endl;
CurrentConditionDisplay::CurrentConditionDisplay()
{
}
void CurrentConditionDisplay::display()
{
cout << "Current conditions:" << m_temp
<< " F degrees and " << m_humidity
<< "% humidity" << endl;
}
void CurrentConditionDisplay::update(double temp, double humidity, double pressure)
{
m_temp = temp;
m_humidity = humidity;
m_pressure = pressure;
display();
}
ForecastDisplay::ForecastDisplay()
{
}
void ForecastDisplay::display()
{
cout << "Forecast: ";
if (currentPressure > lastPressure)
{
cout << "Improving weather on the way!";
}
else if (currentPressure == lastPressure)
{
cout << "More of the same";
}
else if (currentPressure < lastPressure)
{
cout << "Watch out for cooler, rainy weather";
}
cout << endl;
}
void ForecastDisplay::update(double temp, double humidity, double pressure)
{
lastPressure = currentPressure;
currentPressure = pressure;
display();
}
HeatIndexDisplay::HeatIndexDisplay()
{
}
void HeatIndexDisplay::display()
{
cout << "Heat index is " << m_heatIndex << endl;
}
void HeatIndexDisplay::update(double temp, double humidity, double pressure)
{
(void) pressure;
m_heatIndex = computeHeatIndex(temp, humidity);
display();
}
double HeatIndexDisplay::computeHeatIndex(double t, double rh)
{
double index = (double)((16.923 + (0.185212 * t) + (5.37941 * rh) - (0.100254 * t * rh)
+ (0.00941695 * (t * t)) + (0.00728898 * (rh * rh))
+ (0.000345372 * (t * t * rh)) - (0.000814971 * (t * rh * rh)) +
(0.0000102102 * (t * t * rh * rh)) - (0.000038646 * (t * t * t)) + (0.0000291583 *
(rh * rh * rh)) + (0.00000142721 * (t * t * t * rh)) +
(0.000000197483 * (t * rh * rh * rh)) - (0.0000000218429 * (t * t * t * rh * rh)) +
0.000000000843296 * (t * t * rh * rh * rh)) -
(0.0000000000481975 * (t * t * t * rh * rh * rh)));
return index;
}
StatisticsDisplay::StatisticsDisplay():
m_tempSum(0.0),
m_maxTemp(0),
m_minTemp(200),
m_numReadings(0)
{
}
void StatisticsDisplay::display()
{
cout << "Avg/Max/Min temperature = " << m_tempSum / m_numReadings
<< "/" << m_maxTemp << "/" << m_minTemp << endl;
}
void StatisticsDisplay::update(double temp, double humidity, double pressure)
{
(void) humidity;
(void) pressure;
m_tempSum += temp;
m_numReadings++;
if (temp > m_maxTemp)
{
m_maxTemp = temp;
}
if (temp < m_minTemp)
{
m_minTemp = temp;
}
display();
}
最後是測試程式碼:
int main(int argc, char *argv[])
{
WeatherData weatherData;
CurrentConditionDisplay currentDisplay;
StatisticsDisplay staticDisplay;
ForecastDisplay forcastDisplay;
HeatIndexDisplay heatDisplay;
weatherData.registerObserver(¤tDisplay);
weatherData.registerObserver(&staticDisplay);
weatherData.registerObserver(&heatDisplay);
weatherData.registerObserver(&forcastDisplay);
weatherData.setMeasurements(80, 65, 30.4);
weatherData.setMeasurements(82, 70, 29.2f);
weatherData.setMeasurements(78, 90, 29.2f);
}