I am writing an observer design pattern that is not too complex but I still feel there's a lot for me to learn about C++ be it little details (especially coming from C).
A couple of observations:
- I wanted to understand was
Subject
here isn't an abstract class unlikeObserver
however I would ideally have caller instantiateSubject
and rather a concrete Subject class (i.e child class ofSubject
) for which I specified its constructor to beprotected
. For instance,Weather
class being a concrete Subject updates all its observers upon getting a weather data hence the instantiation ofWeather
in the caller - raw pointers (just like here) are fine as long as they're not owning right? If so, I wouldn't need smart pointers perhaps (?) specially if I don't want the object in the caller to be 'owned' by
Subject
? - I used
std::set
overstd::vector
to avoid storing duplicates
template<typename T>
class Observer
{
public:
virtual void update(T val) = 0;
virtual ~Observer() = default;
};
template<typename T>
class Subject
{
std::set<Observer<T>*> _observers;
protected:
Subject() = default;
public:
void attach(Observer<T>* observer)
{
_observers.insert(observer);
}
void detach(Observer<T>* observer)
{
_observers.erase(observer);
}
void notify(const T& val)
{
for (auto& observer : _observers)
{
observer->update(val);
}
}
virtual ~Subject() = default;
};
Main feedback is requested for the above snippet but adding the following to see how the whole pattern could be used:
template<typename T>
class ConcreteSubject : public Subject<T>
{
T _value;
public:
void set(const T& value)
{
_value = value;
this->notify(value);
}
};
template<typename T>
class ConcreteObserver : public Observer<T>
{
public:
void update(T value)
{
std::cout << "Notified: " << value << "\n";
}
};
int main()
{
ConcreteObserver<int> obs;
ConcreteSubject<int> sub;
sub.attach(&obs);
sub.set(5);
return 0;
}