Observer and Observable¶
To write output messages when desired by the user, the observer pattern is implemented in Ikarus.
Four things are necessary to understand the implementation of observer patterns: Messages
, IObservable
,
IObserver
and Subscriptions
.
Messages¶
A message class is a list of possible events that can happen and might be of interest. The messages that are used for nonlinear solvers are listed below as an example.
enum class NonLinearSolverMessages {
BEGIN,
INIT,
ITERATION_STARTED,
ITERATION_ENDED,
RESIDUALNORM_UPDATED,
CORRECTIONNORM_UPDATED,
SOLUTION_CHANGED,
FINISHED_SUCESSFULLY,
END
};
IObservable¶
A class can be observable. The class then sends notifications when events are happening. To become observable, a class
must inherit from IObservable<MessageType>
, for example,
The function this->notify(MessageType::Message)
is called at the appropriate position in the code to send a
notification. This could be, for example,
IObserver¶
A class can be an observer. The class is then notified when events are happening and can perform actions. A very simple
example is shown below. To become an observer, the class must inherit from IObserver<MessageType>
, where MessageType
is the enum
of messages to use (see above).
class OurFirstObserver : public IObserver<NonLinearSolverMessages> {
public:
void updateImpl(NonLinearSolverMessages message) override {
if (message == NonLinearSolverMessages::ITERATION_STARTED) std::cout << "Iteration started.\n";
}
};
The observer has to implement the function void updateImpl(MessageType message)
. In this function, all actions can
be implemented that should be performed when the corresponding message is received.
To connect observer and observable, one has to call observalbe.subscribe(MessageType::Message,observer)
. Example:
Ikarus::NewtonRaphson nr(...);
auto ourSimpleObserver = std::make_shared<OurFirstObserver>();
nr.subscribe(NonLinearSolverMessages::ITERATION_STARTED, ourSimpleObserver);
};
Subscriptions¶
There are a couple of options for the subscription:
subscribe(MessageType::Message,observer) // (1)!
subscribeAll(observer) // (2)!
subscribeAll({observer1,observer2}) // (3)!
unSubscribe(...) // (4)!
- Subscribe to one specific message.
- Subscribes to all the messages in
enum
. - Multiple observers can subscribe at once.
- Unsubscribe from specific messages or all messages.
To send a message together with data, the sender (observable) calls
and the receiver (observer) has to implement
To see all available options for data
, we refer to the file observer.hh
.