#include <iostream>
#include <set>
class Observer
{
public:
virtual void update() = 0;
};
class Subject
{
std::set<Observer*> observers;
public:
void addObserver(Observer* observer)
{
observers.insert(observer);
}
void deleteObserver(Observer* observer)
{
observers.erase(observer);
}
void notifyObservers()
{
for (auto observer : observers)
observer->update();
}
};
class HaveValue1 { public: virtual int getValue1() const = 0; };
class HaveValue2 { public: virtual int getValue2() const = 0; };
class ObservingForValue1 : public Observer
{
HaveValue1* subject;
public:
ObservingForValue1(HaveValue1* subject) : subject(subject) {}
virtual void update()
{
std::cout << "New value of Value1: " << subject->getValue1() << '\n';
}
};
class ObservingForValue2 : public Observer
{
HaveValue2* subject;
public:
ObservingForValue2(HaveValue2* subject) : subject(subject) {}
virtual void update()
{
std::cout << "New value of Value2: " << subject->getValue2() << '\n';
}
};
class UsingInheritance : public HaveValue1, public HaveValue2, public Subject
{
int value1;
int value2;
public:
UsingInheritance(int value1, int value2) : value1(value1), value2(value2) {}
void setValue1(int value) { value1 = value; notifyObservers(); }
void setValue2(int value) { value2 = value; notifyObservers(); }
virtual int getValue1() const override { return value1; }
virtual int getValue2() const override { return value2; }
};
class UsingComposition : public HaveValue1, public HaveValue2
{
int value1;
int value2;
Subject observersForValue1;
Subject observersForValue2;
public:
UsingComposition(int value1, int value2) : value1(value1), value2(value2) {}
void observeValue1(Observer* observer) { observersForValue1.addObserver(observer); }
void observeValue2(Observer* observer) { observersForValue2.addObserver(observer); }
void unobserveValue1(Observer* observer) { observersForValue1.deleteObserver(observer); }
void unobserveValue2(Observer* observer) { observersForValue2.deleteObserver(observer); }
void setValue1(int value)
{ value1 = value; observersForValue1.notifyObservers(); }
void setValue2(int value)
{ value2 = value; observersForValue2.notifyObservers(); }
virtual int getValue1() const override { return value1; }
virtual int getValue2() const override { return value2; }
};
int main()
{
std::cout << "With Inheritance:\n";
UsingInheritance inheritance{ 1, 2 };
ObservingForValue1 io1{ &inheritance };
ObservingForValue2 io2{ &inheritance };
inheritance.addObserver(&io1);
inheritance.addObserver(&io2);
inheritance.setValue1(11);
inheritance.setValue2(22);
std::cout << "\nWith Composition:\n";
UsingComposition composition{ 1, 2 };
ObservingForValue1 co1{ &composition };
ObservingForValue2 co2{ &composition };
composition.observeValue1(&co1);
composition.observeValue2(&co2);
composition.setValue1(11);
composition.setValue2(22);
}
Output:
With Inheritance:
New value of Value2: 2
New value of Value1: 11
New value of Value2: 22
New value of Value1: 11
With Composition:
New value of Value1: 11
New value of Value2: 22
I've learned the observer
pattern from many sources, yet none of them mentioned implementing it with composition. I think using composition is more powerful than inheritance for couple of reasons:
1 - A class can have lots of observers and each one observing for a different thing. If I wanted to achieve the same behavior (having different observers observing n
different things), I'll have to change the base class so that it supports n
types of observers and later on, if I wanted it to support n + 1
observers, I'll have to change it again or inherit from another class. Whereas when using composition, I can just add another Subject
and that's it.
2 - With inheritance if I wanted to notify the observers, I'll notify all the subscribed ones, even if each one of them is looking for a different thing. Whereas when using composition, I can just notify the desired ones.
3 - Composition is prefered over inheritance anyways. If some behavior is achievable using both inheritance and composition, Why the inheritance approach is more popular?
In the code above, I have an Observer
and a Subject
. There are 2 types of Subject
, one using inheritance called UsingInheritance
, and the other uses composition, called UsingComposition
. Each one of them has 2 values, value1
and value2
. There are 2 observers, ObservingForValue1
which is only interested in value1
and ObservingForValue2
which is only interested in value2
. Notice that when using UsingInheritance
, all the subscribed observers get notified even if the value they're interested in didn't change, whereas when using UsingComposition
, only the desired ones get updated.
Aucun commentaire:
Enregistrer un commentaire