|
#ifndef __WEATHER_FORECAST_H__
#define __WEATHER_FORECAST_H__
#include "tool_observer.h"
////////////////////////////////////////////
// class Strategy
//
// Strategy is a very simple subject.
//
class Strategy
{
public:
// Define the type of our "subject". This defines also the interface of
// the observers.
typedef tool::SimpleSubject<> StrategySource;
// Export part of the "subjects" interface using delegation
bool AttachObserver( StrategySource::IObserver* pObserver )
{
return m_StrategySource.AttachObserver( pObserver );
}
bool DetachObserver( StrategySource::IObserver* pObserver )
{
return m_StrategySource.DetachObserver( pObserver );
}
void StrategyChanged()
{
std::cout << "Strategy::StrategyChanged(), notifying observers >>>" << std::endl;
// Notify all observers
m_StrategySource.NotifyObserver();
std::cout << "<<< Strategy::StrategyChanged(), finished notifying observers" << std::endl;
}
private:
// Our subject implementation
StrategySource m_StrategySource;
};
////////////////////////////////////////////
// class TempSens
//
// TempSens is a more sophisticated subject. It implements two subjects for different
// parts of the temperature sensor component:
// 1: A subject for physical state events, like power failure (TechSource)
// 2: A subject for temperature change events (TempSource)
//
class TempSens
{
public:
// The TechSource subject passes some event type information to the observers.
// For this we adopt the ARG1 template argument of our SimpleSubject to techevent_t
// Note that we don't need the OBSERVER_INFO and RETURN template arguments at all.
// However, because you must pass a type for them, we simply use int.
enum techevent_t { ePowerFailure, eOtherFailure };
typedef tool::SimpleSubject< int, int, techevent_t > TechSource;
// The TempSource subject is a more sophisticated subject that uses the OBSERVER_INFO
// stored with each observer. We use this to implement a threshold value. An observer is
// only notified if the new temperature value is equal or above the threshold. To implement
// this we need to override SimpleSubject::NotifyObserver. However, this is not very much work:
struct TempSource : public tool::SimpleSubject< double, int, double >
{
virtual void NotifyObserver( double fNewTemp )
{
for( clients_t::iterator i = m_aObservers.begin(); i != m_aObservers.end(); ++i )
// Call Update only if new Temperature is equal or above the stored threshold
if( i->Info <= fNewTemp )
i->pObserver->Update( fNewTemp );
}
};
bool AttachTechObserver( TechSource::IObserver* pObserver )
{
return m_TechSource.AttachObserver( pObserver );
}
bool DetachTechObserver( TechSource::IObserver* pObserver )
{
return m_TechSource.DetachObserver( pObserver );
}
bool AttachTempObserver( TempSource::IObserver* pObserver, double fThreshold )
{
return m_TempSource.AttachObserver( pObserver, fThreshold );
}
bool DetachTempObserver( TempSource::IObserver* pObserver )
{
return m_TempSource.DetachObserver( pObserver );
}
void SetTemp( double fTemp )
{
std::cout << "TempSens::SetTemp(), notifying observers >>>" << std::endl;
// Notify all observer
m_TempSource.NotifyObserver( fTemp );
std::cout << "<<< TempSens::SetTemp(), finished notifying observers" << std::endl;
}
void TechEvent( techevent_t event )
{
std::cout << "TempSens::TechEvent(), notifying observers >>>" << std::endl;
// Notify all observer
m_TechSource.NotifyObserver( event );
std::cout << "<<< TempSens::TechEvent(), finished notifying observers" << std::endl;
}
private:
TechSource m_TechSource;
TempSource m_TempSource;
};
class Technician
{
public:
Technician()
: m_pTempSens( NULL )
{}
~Technician()
{
// Remove ourself from the list of observers
if( m_pTempSens )
m_pTempSens->DetachTechObserver( &m_Adapter );
}
void SetTempSensor( TempSens* pTempSens )
{
// Add ourself as observer to the passed sensor. To be an observer
// of the passed sensor we have to implement the sensors IObserver interface.
// However, we use an adapter that implements the interface and delegates calls
// to our member fn SomethingHappened
if( m_pTempSens )
// Remove old observing
m_pTempSens->DetachTechObserver( &m_Adapter );
m_pTempSens = pTempSens;
if( m_pTempSens ) {
m_Adapter.SetUpdate( this, &Technician::SomethingHappened );
m_pTempSens->AttachTechObserver( &m_Adapter );
}
}
private:
// This is the member function used as callback
int SomethingHappened( TempSens::techevent_t what )
{
std::cout << "Technician::SomethingHappened() :";
switch( what )
{
case TempSens::ePowerFailure:
std::cout << "Power Failure reported" << std::endl;
break;
case TempSens::eOtherFailure:
std::cout << "Generic Failure reported" << std::endl;
break;
default:
std::cout << "UNKNOWN EVENT!" << std::endl;
break;
}
return 0; // Return value is ignored
}
tool::ObserverAdapter< Technician, TempSens::TechSource > m_Adapter;
TempSens* m_pTempSens;
};
class HurrDet
{
public:
HurrDet()
: m_pTempSens( NULL ), m_pStrategy( NULL )
{}
~HurrDet()
{
if( m_pTempSens )
m_pTempSens->DetachTempObserver( &m_TempAdapter );
if( m_pStrategy )
m_pStrategy->DetachObserver( &m_StrategyAdapter );
}
void SetTempSensor( TempSens* pTempSens, double fThreshold)
{
if( m_pTempSens )
// Remove old observing
m_pTempSens->DetachTempObserver( &m_TempAdapter );
m_pTempSens = pTempSens;
if( m_pTempSens ) {
m_TempAdapter.SetUpdate( this, &HurrDet::OnNewTemp );
m_pTempSens->AttachTempObserver( &m_TempAdapter, fThreshold );
}
}
void SetStrategy( Strategy* pStrategy )
{
if( m_pStrategy )
// Remove old observing
m_pStrategy->DetachObserver( &m_StrategyAdapter );
m_pStrategy = pStrategy;
if( m_pStrategy ) {
m_StrategyAdapter.SetUpdate( this, &HurrDet::OnNewStrategy );
m_pStrategy->AttachObserver( &m_StrategyAdapter );
}
}
private:
// Member function used as callback for "temperature changed" events.
int OnNewTemp( double fNewTemp )
{
std::cout << "HurrDet::OnNewTemp( " << fNewTemp << " )" << std::endl;
return 0; // Return value is ignored
}
// Member function used as callback for "strategy changed" events. Note that
// Strategy does not use the single parameter that can be passed to the observers.
// However, because we pass the arguments type as template parameter to ISubject
// (and therefore to the derived SimpleSubject class) there must be an argument in
// the notify fn signature. But we can ignore the value.
int OnNewStrategy( int )
{
// Parameter is ignored
std::cout << "HurrDet::OnNewStrategy()" << std::endl;
return 0; // Return value is ignored
}
TempSens* m_pTempSens;
Strategy* m_pStrategy;
tool::ObserverAdapter< HurrDet, TempSens::TempSource > m_TempAdapter;
tool::ObserverAdapter< HurrDet, Strategy::StrategySource > m_StrategyAdapter;
};
#endif // __WEATHER_FORECAST_H__
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
Daniel Lohmann (
daniel@losoft.de) is Assistant Professor at the
Distributed Systems and Operating Systems department at Friedrich-Alexander-University Erlangen-Nuremberg, Germany. His main research topic is the design of a highly customizable and scalable operating system product line for deeply embedded systems using static configuration and aspect-oriented techniques. Before joining Universität Erlangen he worked as a freelance trainer and consultant for NT system programming, advanced C++ programming and OOA/OOD. He is interested in upcoming programming techniques like aspect-oriented programming, generative programming and C++ meta coding and has written some nice and handy tools for Windows NT which you can download at his
web site.