Override virtual function with more parameters - c++

I have an array of happy people.
Each happy person has a virtual function called updateHappiness() which is used to update their happiness attribute.
Each person likes their own thing.
Rain lovers are happy persons who really like hearing the sound of the rain and it increases their happiness level. They inherit from the happy person class.
As a consequence, they need to know when it is raining while updating their happiness by overloading the updateHappiness() function with updateHappiness(bool isRaining) as in this post : overload virtual function with different parameters in c++, however, this is a problem because there are many kinds of people and we would like to update them all by calling the same function for every person.
We could have the parameter stored inside of the person class and pass it in the class constructor as in this post : Override number of parameters of pure virtual functions however rain is not a constant state and we would have to call a function updateRainState(bool isRaining) which would cause the same problem as before.
We could pass the parameter bool isRaining to every person even though they don't care about the rain but it would also be a problem because some people like the rain, some people like seeing the daylight, some people like it when their friends are happy... so it would add many useless parameters and it seems like a waste.
Finally, the best solution I could think of is to have a static function in the weather class to get the rain state without passing it as a parameter but it would look like a global variable and some people say that it is really bad!
What would you do to solve this problem ?
Here is an example code of what the classes are like :
class HappyPerson
{
public:
HappyPerson(): m_happinness(0) {}
virtual void updateHappinness() { m_happinness++; }
protected:
int m_happinness;
};
class Weather
{
public:
static int isRaining() { return raining; }
private:
static bool raining;
};
bool Weather::raining(0);
class RainLover : public HappyPerson
{
public:
RainLover() : HappyPerson() {}
void updateHappinness() { m_happinness++; if (Weather::isRaining()) m_happinness++; }
};
int main()
{
std::vector<HappyPerson*> happyPeople;
happyPeople.push_back(new RainLover);
// ... add many other persons
std::vector<HappyPerson*>::iterator it;
for (it = happyPeople.begin(); it != happyPeople.end(); it++)
{
(*it)->updateHappinness();
}
}

You should consider taking a completely different approach - use event callbacks instead.
When something in particular changes, only interested people are affected, so you should not waste time and effect trying to passing around the change to everyone else.
If a person's happiness depends on the Weather, then have the person register for Weather change events.
If a person's happiness depends on another person's happiness, then have the person register for the other person's happiness change events.
And so on.
For example:
class HappyPerson;
class HappinessChangeListener
{
public:
void happinessChanged(HappyPerson *person, bool isHappier) = 0;
};
class HappyPerson
{
public:
HappyPerson();
virtual ~HappyPerson() {}
void updateHappiness(int amount);
void registerHappinessChangeListener(HappinessChangeListener *listener);
void unregisterHappinessChangeListener(HappinessChangeListener *listener);
);
protected:
int m_happinness;
std::vector<HappinessChangeListener*> happinessChangeListeners;
void happinessChanged(bool isHappier);
};
...
HappyPerson::HappyPerson()
: m_happinness(0)
{
}
void HappyPerson::updateHappiness(int amount)
{
if (amount != 0)
{
m_happinness += amount;
happinessChanged(amount > 0);
}
}
void HappyPerson::registerHappinessChangeListener(HappinessChangeListener *listener)
{
happinessChangeListeners.push_back(listener);
}
void HappyPerson::unregisterHappinessChangeListener(HappinessChangeListener *listener)
{
std::vector<HappinessChangeListener*>::iterator i = std::find(happinessChangeListeners.begin(), happinessChangeListeners.end(), listener);
if (i != happinessChangeListeners.end())
happinessChangeListeners.erase(i);
}
void HappyPerson::happinessChanged(bool isHappier)
{
for(std::vector<HappinessChangeListener*>::iterator i = happinessChangeListeners.begin(); i != happinessChangeListeners.end(); ++i)
i->happinessChanged(this, isHappier);
}
class Weather;
class WeatherChangeListener
{
public:
void weatherChanged(Weather *weather) = 0;
};
class Weather
{
public:
Weather();
void rainStarted();
void rainStopped();
bool isRaining();
void registerWeatherChangeListener(WeatherChangeListener *listener);
void unregisterWeatherChangeListener(WeatherChangeListener *listener);
protected:
bool m_raining;
std::vector<WeatherChangeListener*> weatherChangeListeners;
void weatherChanged();
};
...
Weather::Weather()
: m_raining(false)
{
}
void Weather::rainStarted()
{
if (!m_rRaining)
{
m_rRaining = true;
weatherChanged();
}
}
void Weather::rainStopped()
{
if (m_rRaining)
{
m_rRaining = false;
weatherChanged();
}
}
bool Weather::isRaining()
{
return m_raining;
}
void Weather::registerWeatherChangeListener(WeatherChangeListener *listener)
{
weatherChangeListeners.push_back(listener);
}
void Weather::unregisterWeatherChangeListener(WeatherChangeListener *listener)
{
std::vector<WeatherChangeListener*>::iterator i = std::find(weatherChangeListeners.begin(), weatherChangeListeners.end(), listener);
if (i != weatherChangeListeners.end())
weatherChangeListeners.erase(i);
}
void Weather::weatherChanged()
{
for(std::vector<WeatherChangeListener*>::iterator i = weatherChangeListeners.begin(); i != weatherChangeListeners.end(); ++i)
i->weatherChanged(this);
}
class RainLover : public HappyPerson, public WeatherChangeListener
{
public:
RainLover(std::shared_ptr<Weather> &weather);
~RainLover();
void weatherChanged(Weather *weather);
protected:
std::shared_ptr<Weather> m_weather;
};
...
RainLover::RainLover(std::shared_ptr<Weather> &weather)
: HappyPerson(), m_weather(weather)
{
m_weather->registerWeatherChangeListener(this);
}
RainLover::~RainLover()
{
m_weather->unregisterWeatherChangeListener(this);
}
void RainLover::weatherChanged(Weather *weather)
{
updateHappiness(weather->isRaining() ? 1 : -1);
}
class HappyLover : public HappyPerson, public HappinessChangeListener
{
public:
HappyLover(std::shared_ptr<HappyPerson> &person);
~HappyLover();
void happinessChanged(HappyPerson *person, bool isHappier);
protected:
std::shared_ptr<HappyPerson> m_person;
};
...
HappyLover::HappyLover(std::shared_ptr<HappyPerson> &person)
: HappyPerson(), m_person(person)
{
m_person->registerHappinessChangeListener(this);
}
HappyLover::~HappyLover()
{
m_person->unregisterHappinessChangeListener(this);
}
void HappyLover::happinessChanged(HappyPerson *person, bool isHappier)
{
updateHappiness(isHappier ? 1 : -1);
}
int main()
{
std::shared_ptr<Weather> weather(new Weather);
std::vector<std::shared_ptr<HappyPerson>> happyPeople;
happyPeople.push_back(std::shared_ptr<HappyPerson>(new RainLover(weather)));
// or: happyPeople.push_back(std::make_shared<RainLover>(weather));
happyPeople.push_back(std::shared_ptr<HappyPerson>(new HappyLover(happyPeople[0])));
// or: happyPeople.push_back(std::make_shared_ptr<HappyLover>(happyPeople[0]));
// ... add many other persons
weather->rainStarted();
...
weather->rainStopped();
...
}

Related

identifying the design pattern name used

I want to check if the examples below (from a test interview) corresponds to the correct design pattern name :
Example 1 : can that piece of code illustrate the "Builder" pattern or it might be the "Strategy" one ?
FileStream* files = new FileStream("my_file.zip");
BufferedStream* bufferds = new BufferedStream(files);
ZipStream* zips = new ZipStream(bufferds);
Example 2 : is the code below represent the "Strategy" pattern ?
struct UnixText {
void write(string str) { cout << str; }
void lf() { cout << "\n"; }
};
struct WindowsText {
void write(string str) { cout << str; }
void crlf() { cout << "\r\n"; }
};
struct Writer {
virtual void write(string str) = 0;
virtual void newline() = 0;
virtual ~Writer() {}
};
struct UnixWriter : Writer {
UnixWriter(UnixText* tx) { _target = tx; }
virtual void write(string str) { _target->write(str); }
virtual void newline() { _target->lf(); }
private:
UnixText* _target;
};
struct WindowsWriter : Writer {
WindowsWriter(WindowsText* tx) { _target = tx; }
virtual void write(string str) { _target->write(str); }
virtual void newline() { _target->crlf(); }
private:
WindowsText* _target;
};
int main()
{
Writer* writer = (g_IsUnix) ? (Writer*) new UnixWriter(new UnixText()) : (Writer*) new WindowsWriter(new WindowsText());
writer->write("Hello");
writer->newline();
writer->write("World");
}
The first example uses I/O streams and it is a good use of Decorator pattern. Here it has a constructor that takes an instance of the same abstract class or interface. That's the recognition key of the Decorator pattern
The second one, you are passing some Writing Strategy to the UnixWriter and WindowsWriter which is the context. So it can be considered as Strategy pattern. But you can still improve it by having a contract for Writing Strategy. So your concrete writers should only know about that super type rather than having references to concrete implementations. That will make your system more flexible.

Using a static variable in an abstract base class

I am trying to create a state machine. I have created a class called BaseState that all states inherits from. The problem I'm having is that when the sub classes change a BaseState member variable, it does not change the variable for all of the inherited classes. From what I know of programming, this is when I use static. But in my case I get a linker error (LNK2001).
So when I call ChangeState(State::MenuState); inside SplashState, it switches, but switches back since the value in BaseState has not changed.
class StateMachine
{
private:
State _currentState;
std::vector<BaseState*> _baseStates;
void ProcessStateRequest();
public:
StateMachine(InitVar initVar);
~StateMachine();
void Update(float deltaTime);
};
That adds the states like this:
StateMachine::StateMachine(InitVar initVar)
{
_currentState = State::SPLASHSTATE;
for (int i = 0; i < State::EXITSTATE; i++)
{
switch (i)
{
case SPLASHSTATE:
{
_baseStates.push_back(new SplashState(initVar));
break;
}
case MENUSTATE:
{
_baseStates.push_back(new MenuState(initVar));
break;
}
case PLAYSTATE:
{
_baseStates.push_back(new PlayState(initVar));
break;
}
case OPTIONSSTATE:
{
_baseStates.push_back(new OptionsState(initVar));
break;
}
}
}
}
With changing states like this:
void StateMachine::ProcessStateRequest()
{
//if currentState does not match with the new requested state.
if (_currentState != _baseStates[_currentState]->GetNewStateRequest())
{
_baseStates[_currentState]->OnStateExit();
_currentState = _baseStates[_currentState]->GetNewStateRequest();
_baseStates[_currentState]->OnStateEnter();
}
}
Inside basestate.h:
enum State
{
SPLASHSTATE,
MENUSTATE,
PLAYSTATE,
OPTIONSSTATE,
EXITSTATE,
};
class BaseState
{
private:
State _newStateRequest; //Cannot edit this from subclasses. Adding static causes linker error.
protected:
ObjectHandler* _objectHandler;
UIHandler* _uiHandler;
void ChangeState(State newState);
public:
BaseState(InitVar initVar);
~BaseState();
virtual void Update(float deltaTime) = 0;
virtual void OnStateEnter() = 0;
virtual void OnStateExit() = 0;
State GetNewStateRequest()const;
};
The last part of basestate.cpp:
BaseState::BaseState(InitVar initVar)
{
_objectHandler = initVar.objectHandler;
_uiHandler = initVar.uiHandler;
_newStateRequest = SPLASHSTATE;
}
BaseState::~BaseState()
{}
void BaseState::ChangeState(State newState)
{
_newStateRequest = newState;
}
State BaseState::GetNewStateRequest() const
{
return _newStateRequest;
}
MikeCAT in comments gave this answer. Problem solved by doing this;
class BaseState
{
private:
static State BaseState::_newStateRequest;
//State _newStateRequest;
and
#include "BaseState.h"
State BaseState::_newStateRequest;
BaseState::BaseState(InitVar initVar)

Inheritance, defining a function for creating an object of a specified type?

Title does not help im sure.
Anyway, at the moment i'm working with the following
http://puu.sh/7wJed.png
Everything's fine and inherited correctly, however, in order to create an object of say 'aircraftCarrier' i'd need to pass the 12 values + the two inherited values every-time i want to use a function such as
generateAirCraftCarrier(1,2,3,4,5,6,7,8,9,10,11,12);
I could simply pass in a navalVessel instance into the function instead, such that
generateAirCraftCarrier(myNavalVessel, inherit var 1, inherit var 2);
BUT this would not be entirely a solution because what happens when the aircraft carrier has a different 'Speed' for example?
can i have option parameters, which if null use the myNavalVessel object? Looking for some guidance here, sorry about the gibberish.
Why do you need one function to define all 12 values on an AircraftCarrier? Why not build it up with a number of setters on AircraftCarrier and NavalVessel? e.g:
class NavalVessel {
float speed_;
public:
void setSpeed(float speed) { speed_ = speed; }
};
class AircraftCarrier : public NavalVessel {
int noHeliPads_;
int noRunways_;
public:
void setNoHeliPads(int noHeliPads) { noHeliPads_ = noHeliPads; }
void setNoRunways(int noRunways) { noRunways_ = noRunways; }
};
int main() {
AircraftCarrier aircraftCarrier;
aircraftCarrier.setSpeed(25.3);
aircraftCarrier.setNoHeliPads(3);
aircraftCarrier.setNoRunways(2);
}
Could named parameters idiom be useful for you?
class AircraftCarrierParameters;
class AircraftCarrier
{
private:
AircraftCarrierParameters _params;
public:
AircraftCarrier(const AircraftCarrierParameters& params)
: _params(params) {}
AircraftCarrierParameters params() const { return _params;}
};
class AircraftCarrierParameters
{
private:
double _speed;
int _someOtherStuff;
public:
AircraftCarrierParameters()
: _speed(0) //default parameters
, _someOtherStuff(0)
{
}
double speed() const { return _speed; }
double someOtherStuff() const { return _someOtherStuff; }
AircraftCarrierParameters& setSpeed(double speed) { _speed = speed; return *this; }
AircraftCarrierParameters& setSomeOtherStuff(double stuff) { _someOtherStuff = stuff; return *this; }
};
AirCraftCarrier generateAirCraftCarrier(const AircraftCarrierParameters& params)
{
//...
}
void main()
{
AircraftCarrier c1(AircraftCarrierParameters());
AircraftCarrier c2(c1.params().setSpeed(30));
}

C++ event handling interface with function pointers

I want to implement a simple event interface with function pointers for a simple game in C++. This will be done to improve the event interface of the allegro lib. Therefore I've written the following code but it doesn't work.
typedef void (*event_handler)(int); //type for the event handler
const int TESTKEY_A = 1; // example Key as event arg
class Game
{
private:
bool is_running ;
protected:
event_handler on_key_down[2];
public:
void run();
void do_events(int e) ;
void stop() {is_running = false;}
};
void Game::run()
{
is_running=true;
while(is_running)
do_events(1);
}
void Game::do_events(int e)
{
if(e==1)
{
for(int i = 0; i < 2 ;i++)
on_key_down[i](TESTKEY_A);
}
}
class Pong_Game : public Game
{
public:
Pong_Game();
void On_Key_Down_Player1(int key) { return;}
void On_Key_Down_Player2(int key) { return;}
};
Pong_Game::Pong_Game()
{
on_key_down[0] = &this->On_Key_Down_Player1;
on_key_down[1] = &this->On_Key_Down_Player2;
}
int main()
{
Game *my_game = new Pong_Game();
my_game->run();
return 0;
}
Compiler log:
Compiler: Default compiler
Executing g++.exe...
g++.exe "U:\Eigene Dateien\eventhandler.cpp" -o "U:\Eigene Dateien\eventhandler.exe" -I"C:\Dev-Cpp\lib\gcc\mingw32\3.4.2\include" -I"C:\Dev-Cpp\include\c++\3.4.2\backward" -I"C:\Dev-Cpp\include\c++\3.4.2\mingw32" -I"C:\Dev-Cpp\include\c++\3.4.2" -I"C:\Dev-Cpp\include" -L"C:\Dev-Cpp\lib"
U:\Eigene Dateien\eventhandler.cpp: In constructor `Pong_Game::Pong_Game()':
U:\Eigene Dateien\eventhandler.cpp:45: error: ISO C++ forbids taking the address of a bound member function to form a pointer to member function. Say `&Pong_Game::On_Key_Down_Player1'
U:\Eigene Dateien\eventhandler.cpp:45: error: cannot convert `void (Pong_Game::*)(int)' to `void (*)(int)' in assignment
U:\Eigene Dateien\eventhandler.cpp:46: error: ISO C++ forbids taking the address of a bound member function to form a pointer to member function. Say `&Pong_Game::On_Key_Down_Player2'
U:\Eigene Dateien\eventhandler.cpp:46: error: cannot convert `void (Pong_Game::*)(int)' to `void (*)(int)' in assignment
Execution terminated
EDIT:
- changed code
- added compiler log
Thank you!
You are using a member function to initialize a "plain" function pointer. Member functions are different from "plain" functions in that they have a hidden T *this passed along with the function.
This seems like something that would be MUCH better solved by having a "event handler" interface, implemented by inheritance, than using function pointers.
Something like this:
class Game
{
private:
bool is_running ;
public:
void run(){is_running=true; while(is_running) do_events(1);}
void do_events(int e) {if(e==1) On_Key_Down(TESTKEY_A);}
void stop() {is_running = false;}
virtual void On_Key_Down(int key) = 0;
... other event handlers here ...
};
class Pong_Game : public Game
{
public:
void Pong_Game() {}
void On_Key_Down(int key) { // handle key event...}
... other event handlers here ...
};
As per comments:
To cover multiple players, you may want to implement a "per player event handling":
class Player
{
public:
enum moves { move_up,
move_down,
move_left,
move_right,
move_jump,
move_shoot, ... };
...
virtual void On_Key_Down(int key) = 0;
...
};
class Player_A
{
public:
...
virtual moves On_Key_Down(int key) { if (key == 'W') return move_up; ... }
}
class Player_B
{
public:
...
virtual moves On_Key_Down(int key) { if (key == 'I') return move_up; ... }
}
class Pong_Game : public Game
{
private:
vector<Player *> players;
public:
void Pong_Game() {}
void On_Key_Down(int key)
{
for(p : players) {
Player::moves m = p->On_key_down();
...
}
}
... other event handlers here ...
};
(This is just quickly hacked up - the "moves" may perhaps be better placed somewhere else, and the exact structure is just "what I could think of right now" - you probably need a class Player_A_Pong : public Player_A or some such to deal with the specifics of "player A's racket is here, player B's racket is here..." - although there are probably other ways to deal with that too).

Implementing Observer pattern when observers wish to observe different items

Below I have attempted to write a sudo code for the Observer pattern when observers wish to observe different items.
Ignore the syntax errors. I wish to know if this is the correct way to implement this. If not, please suggest better ways.
// Used by the subject for keeping a track of what items the observer wants to observe
typedef struct observerListStruct
{
bool getTemperatureUpdate;
bool getHumidityUpdate;
bool getPressureUpdate;
observer's-function pointer's address;
};
// Subject's class
class weatherData
{
public:
// Observers will call this function to register themselves. The function pointer will point to the function which will get called when updates are available.
void registerObservers (observer obj, observer's-FunctionPointer)
{
// This observer's function returns which items to observe.
char* f = obj.returnItemsToObserve ();
if f[0] = `1`
observerListStruct.getTemperatureUpdate = true;
}
void unregisterObservers (observer obj) {}
private:
vector <observerListStruct> observerList;
float temperature;
float humidity;
float pressure;
void notifyObservers () {}
float getTemperature () {}
float getHumidity () {}
float getPressure () {}
} weatherDataObject;
// Base class for observers containing common functions
class observers
{
char ItemsToObserve [3] = {1, 2, 3};
// This observer's function returns which items to observe. Default - return all items
virtual char* returnItemsToObserve ()
{
return ItemsToObserve;
}
};
class observerDisplayElementCurrentConditions : public observers
{
char ItemsToObserve [3] = {1, 2};
char* returnItemsToObserve ()
{
return ItemsToObserve;
}
// this function will be used as a function pointer for getting updates
void getUpdatesAndDisplayWeatherData (float, float) {}
};
A more pattern oriented solution (but without function pointers) could be the following. You could parametrize the WeatherObserver-Class to get only the values, you want.
#include <list>
#include <iostream>
class Observable; //forward declaration
//Base class for all observers
class Observer {
friend class Observable; //allow access to observedSubject
protected:
Observable *observedSubject;
public:
virtual void update(){};
};
//Base class for all observables
class Observable {
private:
std::list<Observer * const> m_registeredObservers;
public:
~Observable()
{
//delete the observers
std::list<Observer * const>::iterator it = m_registeredObservers.begin();
while (it != m_registeredObservers.end())
{
delete *it;
it = m_registeredObservers.erase(it);
}
}
void addObserver(Observer * const _pObserver)
{
_pObserver->observedSubject = this;
m_registeredObservers.push_back(_pObserver);
}
void removeObserver(Observer * const _pObserver)
{
m_registeredObservers.remove(_pObserver);
delete _pObserver;
}
void notifyObservers()
{
std::list<Observer * const>::iterator it = m_registeredObservers.begin();
while (it != m_registeredObservers.end())
{
(*it)->update();
it++;
}
}
};
//Concrete Observable
class WeatherData : public Observable {
private:
float temperature;
float humidity;
float pressure;
public:
WeatherData(): temperature(0), humidity(0), pressure(0)
{};
float getTemperature () const
{
return temperature;
}
float getHumidity () const
{
return humidity;
}
float getPressure () const
{
return pressure;
}
void setTemperature(float _temperature)
{
if (temperature != _temperature)
{
temperature = _temperature;
notifyObservers();
}
}
void setHumidity(float _humidity)
{
if (humidity != _humidity)
{
humidity = _humidity;
notifyObservers();
}
}
void setPressure(float _pressure)
{
if (pressure != _pressure)
{
pressure = _pressure;
notifyObservers();
}
}
};
//Concrete implementation of an weather observer
class WeatherObserver : public Observer
{
public:
WeatherObserver():Observer(){};
void update()
{
WeatherData* pWeatherPtr = static_cast<WeatherData*>(observedSubject);
if (pWeatherPtr != 0)
{
float actHumidity = pWeatherPtr->getHumidity();
float actPressure = pWeatherPtr->getPressure();
float actTemperature = pWeatherPtr->getTemperature();
//do something with the data
std::cout << "WeatherObserver update" << std::endl;
std::cout << "Temperature : " << actTemperature << std::endl;
std::cout << "Humidity : " << actHumidity << std::endl;
std::cout << "Pressure : " << actPressure << std::endl;
}
}
};
int main()
{
WeatherData weatherData;
Observer * pObserver = new WeatherObserver();
weatherData.addObserver(pObserver);
weatherData.setHumidity(100);
weatherData.setTemperature(100);
}
#include <algorithm>
#include <vector>
class WeatherFlags
{
public:
WeatherFlags()
: mask_(0)
{}
union {
struct {
unsigned int temperature_ : 1;
unsigned int humidity_ : 1;
unsigned int pressure_ : 1;
};
unsigned int mask_;
};
};
class WeatherData;
class WeatherEvent
{
public:
WeatherEvent(WeatherData* data, WeatherFlags const& flags)
: data_(data)
, flags_(flags)
{}
double getTemperature() const;
WeatherData* data_;
WeatherFlags flags_;
};
class WeatherListener
{
public:
virtual ~WeatherListener() = 0;
virtual void onWeatherUpdate(WeatherEvent& e) = 0;
};
inline WeatherListener::~WeatherListener() {}
class WeatherListenerEntry
{
public:
WeatherListenerEntry()
: listener_(0)
{}
WeatherListenerEntry(WeatherListener* listener, WeatherFlags const& flags)
: listener_(listener)
, flags_(flags)
{}
WeatherListener* listener_;
WeatherFlags flags_;
};
class WeatherData
{
public:
WeatherData();
void addListener(WeatherListener* listener, WeatherFlags const& flags);
void removeListener(WeatherListener* listener);
void notify(WeatherFlags const& flags);
double getTemperature() const { return temperature_; }
private:
typedef std::vector<WeatherListenerEntry> Listeners;
Listeners listeners_;
double temperature_;
};
WeatherData::WeatherData()
: temperature_(0)
{}
void WeatherData::addListener(WeatherListener* listener, WeatherFlags const& flags)
{
// TODO Could maybe check for the addition of duplicates here...
listeners_.push_back(WeatherListenerEntry(listener, flags));
}
void WeatherData::removeListener(WeatherListener* listener)
{
struct ListenerEquals {
WeatherListener* listener_;
ListenerEquals(WeatherListener* listener)
: listener_(listener)
{}
bool operator()(WeatherListenerEntry const& e) const {
return (e.listener_ == listener_);
}
};
listeners_.erase(
std::remove_if(listeners_.begin(), listeners_.end(), ListenerEquals(listener)),
listeners_.end());
}
void WeatherData::notify(WeatherFlags const& flags)
{
WeatherEvent evt(this, flags);
for (Listeners::iterator i = listeners_.begin(); i != listeners_.end(); ++i)
{
if (0 != (i->flags_.mask_ & flags.mask_)) {
i->listener_->onWeatherUpdate(evt);
}
}
}
double
WeatherEvent::getTemperature() const
{
return data_->getTemperature();
}
#include <iostream>
class WeatherObserverStdout : public WeatherListener
{
public:
void observe(WeatherData& data) {
WeatherFlags flags;
flags.temperature_ = true; // interested in temperature only.
data.addListener(this, flags);
}
virtual void onWeatherUpdate(WeatherEvent& e);
};
void
WeatherObserverStdout::onWeatherUpdate(WeatherEvent& e)
{
double temp = e.getTemperature();
std::cout << "Temperatrure: " << temp << std::endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
WeatherData wdata;
WeatherObserverStdout obs;
obs.observe(wdata);
WeatherFlags flags;
wdata.notify(flags);
flags.temperature_ = true;
wdata.notify(flags);
return 0;
}
I think it is easier, and more scalable, to define a set of event types that each observer can listen to. Then you register the observer to listen to that particular event type. The observed then keeps a list of observers registered for each event, and notifies them if and when the event occurs. Using a combination of std::function, std::bind (or boost equivalents), it is easy to register callbacks for a given event type. You could put the callbacks in a map of event type to callback.
For example, something along these lines (almost pseudo-code, has not been tested)
class Publisher {
public :
void subscribe(const std::string& event,
std::function<void(double)> callback) {
m_subscribers[s].push_back(callback);
}
void publish(const std::string& event) const {
for (auto& f : m_subscribers[event]) f( some double );}
void event(const std::string& event) const { publish(event);}
private:
// map of event types (here simply strings) to list of callbacks
std::map<std::string&,
std::list<std::function<void(const std::string&)>>> m_subscribers;
};
struct Foo {
void foo(double x) {
std::cout << "Foo received message: " << x << "\n";
}
};
struct Bar {
void bar(double x) {
std::cout << "Bar received message: " << x << "\n";
}
};
int main() {
Publisher pub;
Foo f0;
Foo f1;
Bar bar0;
pub.subscribe("RED", std::bind(&Foo::foo, &foo0, _1));
pub.subscribe("GREEN", std::bind(&Foo::foo, &foo1, _1));
pub.subscribe("WHITE", std::bind(&Foo::foo, &foo1, _1));
pub.subscribe("RED", std::bind(&Bar::bar, &bar0, _1));
pub.subscribe("BLUE", std::bind(&Bar::bar, &bar0, _1));
pub.subscribe("MAGENTA", std::bind(&Bar::bar, &bar0, _1));
// trigger a "GREEN" event
pub.event("GREEN");
}
Here, the observers (or subscribers) register to some events, represented by strings here, and their registered callbacks get called when this event happens. In the example above I manually trigger an event to illustrate the mechanism.
This event-callback mechanism allows to decouple the actual items from the callback action. The Observed (or publisher) knows what parameter to pass the callback for a given event, and which callbacks to call, so the observers are not dependent on the internal data of the observed object.
I write a lot of C++ code and needed to create an Observer for some game components I was working on. I needed something to distribute "start of frame", "user input", etc., as events in the game to interested parties.
I also wanted more granularity in the events that could be handled. I have a lot of little things that go off...I don't need to have the parts that are interested in resetting for the next frame worried about a change in the user input.
I also wanted it to be straight C++, not dependent on the platform or a specific technology (such as boost, Qt, etc.) because I often build and re-use components (and the ideas behind them) across different projects.
Here is the rough sketch of what I came up with as a solution:
The Observer is a singleton with keys (enumerated values, not strings; this is a speed tradeoff since the keys are not searched hashed, but it means no easy "string" names and you have to define them ahead of time) for Subjects to register interest in. Because it is a singleton, it always exists.
Each subject is derived from a common base class. The base class has an abstract virtual function Notify(...) which must be implemented in derived classes, and a destructor that removes it from the Observer (which it can always reach) when it is deleted.
Inside the Observer itself, if Detach(...) is called while a Notify(...) is in progress, any detached Subjects end up on a list.
When Notify(...) is called on the Observer, it creates a temporary copy of the Subject list. As it iterates over it, it compare it to the recently detached. If the target is not on it, Notify(...) is called on the target. Otherwise, it is skipped.
Notify(...) in the Observer also keeps track of the depth to handle cascading calls (A notifies B, C, D, and the D.Notify(...) triggers a Notify(...) call to E, etc.)
This is what the interface ended up looking like:
/*
The Notifier is a singleton implementation of the Subject/Observer design
pattern. Any class/instance which wishes to participate as an observer
of an event can derive from the Notified base class and register itself
with the Notiifer for enumerated events.
Notifier derived classes MUST implement the notify function, which has
a prototype of:
void Notify(const NOTIFIED_EVENT_TYPE_T& event)
This is a data object passed from the Notifier class. The structure
passed has a void* in it. There is no illusion of type safety here
and it is the responsibility of the user to ensure it is cast properly.
In most cases, it will be "NULL".
Classes derived from Notified do not need to deregister (though it may
be a good idea to do so) as the base class destructor will attempt to
remove itself from the Notifier system automatically.
The event type is an enumeration and not a string as it is in many
"generic" notification systems. In practical use, this is for a closed
application where the messages will be known at compile time. This allows
us to increase the speed of the delivery by NOT having a
dictionary keyed lookup mechanism. Some loss of generality is implied
by this.
This class/system is NOT thread safe, but could be made so with some
mutex wrappers. It is safe to call Attach/Detach as a consequence
of calling Notify(...).
*/
class Notified;
class Notifier : public SingletonDynamic<Notifier>
{
public:
typedef enum
{
NE_MIN = 0,
NE_DEBUG_BUTTON_PRESSED = NE_MIN,
NE_DEBUG_LINE_DRAW_ADD_LINE_PIXELS,
NE_DEBUG_TOGGLE_VISIBILITY,
NE_DEBUG_MESSAGE,
NE_RESET_DRAW_CYCLE,
NE_VIEWPORT_CHANGED,
NE_MAX,
} NOTIFIED_EVENT_TYPE_T;
private:
typedef vector<NOTIFIED_EVENT_TYPE_T> NOTIFIED_EVENT_TYPE_VECTOR_T;
typedef map<Notified*,NOTIFIED_EVENT_TYPE_VECTOR_T> NOTIFIED_MAP_T;
typedef map<Notified*,NOTIFIED_EVENT_TYPE_VECTOR_T>::iterator NOTIFIED_MAP_ITER_T;
typedef vector<Notified*> NOTIFIED_VECTOR_T;
typedef vector<NOTIFIED_VECTOR_T> NOTIFIED_VECTOR_VECTOR_T;
NOTIFIED_MAP_T _notifiedMap;
NOTIFIED_VECTOR_VECTOR_T _notifiedVector;
NOTIFIED_MAP_ITER_T _mapIter;
// This vector keeps a temporary list of observers that have completely
// detached since the current "Notify(...)" operation began. This is
// to handle the problem where a Notified instance has called Detach(...)
// because of a Notify(...) call. The removed instance could be a dead
// pointer, so don't try to talk to it.
vector<Notified*> _detached;
int32 _notifyDepth;
void RemoveEvent(NOTIFIED_EVENT_TYPE_VECTOR_T& orgEventTypes, NOTIFIED_EVENT_TYPE_T eventType);
void RemoveNotified(NOTIFIED_VECTOR_T& orgNotified, Notified* observer);
public:
virtual void Reset();
virtual bool Init() { Reset(); return true; }
virtual void Shutdown() { Reset(); }
void Attach(Notified* observer, NOTIFIED_EVENT_TYPE_T eventType);
// Detach for a specific event
void Detach(Notified* observer, NOTIFIED_EVENT_TYPE_T eventType);
// Detach for ALL events
void Detach(Notified* observer);
/* The design of this interface is very specific. I could
* create a class to hold all the event data and then the
* method would just have take that object. But then I would
* have to search for every place in the code that created an
* object to be used and make sure it updated the passed in
* object when a member is added to it. This way, a break
* occurs at compile time that must be addressed.
*/
void Notify(NOTIFIED_EVENT_TYPE_T, const void* eventData = NULL);
/* Used for CPPUnit. Could create a Mock...maybe...but this seems
* like it will get the job done with minimal fuss. For now.
*/
// Return all events that this object is registered for.
vector<NOTIFIED_EVENT_TYPE_T> GetEvents(Notified* observer);
// Return all objects registered for this event.
vector<Notified*> GetNotified(NOTIFIED_EVENT_TYPE_T event);
};
/* This is the base class for anything that can receive notifications.
*/
class Notified
{
public:
virtual void Notify(Notifier::NOTIFIED_EVENT_TYPE_T eventType, const void* eventData) = 0;
virtual ~Notified();
};
typedef Notifier::NOTIFIED_EVENT_TYPE_T NOTIFIED_EVENT_TYPE_T;
NOTE: The Notified class has a single function, Notify(...) here. Because the void* is not type safe, I created other versions where notify looks like:
virtual void Notify(Notifier::NOTIFIED_EVENT_TYPE_T eventType, int value);
virtual void Notify(Notifier::NOTIFIED_EVENT_TYPE_T eventType, const string& str);
Corresponding Notify(...) methods were added to the Notifier itself. All these used a single function to get the "target list" then called the appropriate function on the targets. This works well and keeps the receiver from having to do ugly casts.
This seems to work well. The solution is posted on the web here along with the source code. This is a relatively new design, so any feedback is greatly appreciated.
My two cents...
Classic (Gang of Four) implementation of Observer pattern notifies observer on changes in any property of the subject. In your question you want to register observer to particular properties, not to a subject as a whole. You can move Observer pattern one level down and take properties as concrete subjects and define their observers (per property) but there is one nicer way to solve this problem.
In C# Observer pattern is implemented through events and delegates. Delegates represent event handlers - functions that should be executed when an event is fired. Delegates can be added (registered) or removed(unregistered) from events.
In C++, functors act as delegates - they can store all necessary information to call some global function or class method in a different context. Events are collections of (registered) functors and when event is raised (called) it basically goes through that list and calls all functors (see Publisher::publish method in juanchopanza's solution).
I tried to implement C++ version of events and delegates and use them in modified Observer pattern which could be applied in your case. This is what I came up with:
#include <list>
#include <iostream>
#include <algorithm>
// use base class to resolve the problem of how to put into collection objects of different types
template <typename TPropertyType>
struct PropertyChangedDelegateBase
{
virtual ~PropertyChangedDelegateBase(){};
virtual void operator()(const TPropertyType& t) = 0;
};
template <typename THandlerOwner, typename TPropertyType>
struct PropertyChangedDelegate : public PropertyChangedDelegateBase<TPropertyType>
{
THandlerOwner* pHandlerOwner_;
typedef void (THandlerOwner::*TPropertyChangeHandler)(const TPropertyType&);
TPropertyChangeHandler handler_;
public:
PropertyChangedDelegate(THandlerOwner* pHandlerOwner, TPropertyChangeHandler handler) :
pHandlerOwner_(pHandlerOwner), handler_(handler){}
void operator()(const TPropertyType& t)
{
(pHandlerOwner_->*handler_)(t);
}
};
template<typename TPropertyType>
class PropertyChangedEvent
{
public:
virtual ~PropertyChangedEvent(){};
void add(PropertyChangedDelegateBase<TPropertyType>* const d)
{
std::list<PropertyChangedDelegateBase<TPropertyType>* const>::const_iterator it = std::find(observers_.begin(), observers_.end(), d);
if(it != observers_.end())
throw std::runtime_error("Observer already registered");
observers_.push_back(d);
}
void remove(PropertyChangedDelegateBase<TPropertyType>* const d)
{
std::list<PropertyChangedDelegateBase<TPropertyType>* const>::const_iterator it = std::find(observers_.begin(), observers_.end(), d);
if(it != observers_.end())
observers_.remove(d);
}
// notify
void operator()(const TPropertyType& newValue)
{
std::list<PropertyChangedDelegateBase<TPropertyType>* const>::const_iterator it = observers_.begin();
for(; it != observers_.end(); ++it)
{
(*it)->operator()(newValue);
}
}
protected:
std::list<PropertyChangedDelegateBase<TPropertyType>* const> observers_;
};
// class that owns concrete subjects
class PropertyOwner1
{
int property1_;
float property2_;
public:
PropertyChangedEvent<int> property1ChangedEvent;
PropertyChangedEvent<float> property2ChangedEvent;
PropertyOwner1() :
property1_(0),
property2_(0.0f)
{}
int property1() const {return property1_;}
void property1(int n)
{
if(property1_ != n)
{
property1_ = n;
std::cout << "PropertyOwner1::property1(): property1_ set to " << property1_ << std::endl;
property1ChangedEvent(property1_);
}
}
float property2() const {return property2_;}
void property2(float n)
{
if(property2_ != n)
{
property2_ = n;
std::cout << "PropertyOwner1::property2(): property2_ set to " << property2_ << std::endl;
property2ChangedEvent(property2_);
}
}
};
// class that owns concrete subjects
class PropertyOwner2
{
bool property1_;
double property2_;
public:
PropertyChangedEvent<bool> property1ChangedEvent;
PropertyChangedEvent<double> property2ChangedEvent;
PropertyOwner2() :
property1_(false),
property2_(0.0)
{}
bool property1() const {return property1_;}
void property1(bool n)
{
if(property1_ != n)
{
property1_ = n;
std::cout << "PropertyOwner2::property1(): property1_ set to " << property1_ << std::endl;
property1ChangedEvent(property1_);
}
}
double property2() const {return property2_;}
void property2(double n)
{
if(property2_ != n)
{
property2_ = n;
std::cout << "PropertyOwner2::property2(): property2_ set to " << property2_ << std::endl;
property2ChangedEvent(property2_);
}
}
};
// class that observes changes in property1 of PropertyOwner1 and property1 of PropertyOwner2
struct PropertyObserver1
{
void OnPropertyOwner1Property1Changed(const int& newValue)
{
std::cout << "\tPropertyObserver1::OnPropertyOwner1Property1Changed(): \n\tnew value is: " << newValue << std::endl;
}
void OnPropertyOwner2Property1Changed(const bool& newValue)
{
std::cout << "\tPropertyObserver1::OnPropertyOwner2Property1Changed(): \n\tnew value is: " << newValue << std::endl;
}
};
// class that observes changes in property2 of PropertyOwner1 and property2 of PropertyOwner2
struct PropertyObserver2
{
void OnPropertyOwner1Property2Changed(const float& newValue)
{
std::cout << "\tPropertyObserver2::OnPropertyOwner1Property2Changed(): \n\tnew value is: " << newValue << std::endl;
}
void OnPropertyOwner2Property2Changed(const double& newValue)
{
std::cout << "\tPropertyObserver2::OnPropertyOwner2Property2Changed(): \n\tnew value is: " << newValue << std::endl;
}
};
int main(int argc, char** argv)
{
PropertyOwner1 propertyOwner1;
PropertyOwner2 propertyOwner2;
PropertyObserver1 propertyObserver1;
PropertyObserver2 propertyObserver2;
// register observers
PropertyChangedDelegate<PropertyObserver1, int> delegate1(&propertyObserver1, &PropertyObserver1::OnPropertyOwner1Property1Changed);
propertyOwner1.property1ChangedEvent.add(&delegate1);
PropertyChangedDelegate<PropertyObserver2, float> delegate2(&propertyObserver2, &PropertyObserver2::OnPropertyOwner1Property2Changed);
propertyOwner1.property2ChangedEvent.add(&delegate2);
PropertyChangedDelegate<PropertyObserver1, bool> delegate3(&propertyObserver1, &PropertyObserver1::OnPropertyOwner2Property1Changed);
propertyOwner2.property1ChangedEvent.add(&delegate3);
PropertyChangedDelegate<PropertyObserver2, double> delegate4(&propertyObserver2, &PropertyObserver2::OnPropertyOwner2Property2Changed);
propertyOwner2.property2ChangedEvent.add(&delegate4);
propertyOwner1.property1(1);
propertyOwner1.property2(1.2f);
propertyOwner2.property1(true);
propertyOwner2.property2(3.4);
// unregister PropertyObserver1
propertyOwner1.property1ChangedEvent.remove(&delegate1);
propertyOwner2.property1ChangedEvent.remove(&delegate3);
propertyOwner1.property1(2);
propertyOwner1.property2(4.5f);
}
Output:
PropertyOwner1::property1(): property1_ set to 1
PropertyObserver1::OnPropertyOwner1Property1Changed():
new value is: 1
PropertyOwner1::property2(): property2_ set to 1.2
PropertyObserver2::OnPropertyOwner1Property2Changed():
new value is: 1.2
PropertyOwner2::property1(): property1_ set to 1
PropertyObserver1::OnPropertyOwner2Property1Changed():
new value is: 1
PropertyOwner2::property2(): property2_ set to 3.4
PropertyObserver2::OnPropertyOwner2Property2Changed():
new value is: 3.4
PropertyOwner1::property1(): property1_ set to 2
PropertyOwner1::property2(): property2_ set to 4.5
PropertyObserver2::OnPropertyOwner1Property2Changed():
new value is: 4.5
Each observer is registered with a particular property and when notified, each observer knows exactly who is the owner of the property and what's property's new value.