Observer Pattern
Contents
Event-Driven Programming
An order-of-execution independent system (independent of time).
For example:
EventEmitter
in Node.jsconst EventEmitter = require('events');
- Website hooks (Although subscribing is done manually)
Observer Pattern
We can consider this a callback driven system, where you supply function references, which can be called later.
- Parties
- Subject/Observable/Publisher
- Observer/Subscriber
- Subscribe to a subject/observable/publisher
- When a given observable updates, it pushes an update to its subscribers
Can have 'channels' by separating which subscribers are notified for a specific event.
One publisher may have zero to an infinite number of subscribers (1 to many)
A bad approach
Each subscriber adds the publisher to an internal list. Every 'tick' they check the observer.
But this is bad, as it is a very expensive operation.n_subscribers * n_ticks * n_publishers_in_list * ... == alot
.
In addition, we may miss a change if a value in the publisher changes during a tick loop cycle.
Aside: Sometimes we might need to set it up this way, especially when it comes to code split upon multiple machines (ie IoT). Due to network conditions (firewalls, non-persistent connections, etcetera), it may not be possible for the publisher to connect directly to the subscriber.
In that case we could implement something like polling.
A better approach - publish-subscribe
Each subscriber adds a callback to the publisher's list. When the publisher object is updated, each client is notified.
1_event * n_subscribers == not alot!
Aside: java.util.Observer
and java.util.Observable
- Requires an inheritance
Observable
is a class, not an interface?Observable
protects itssetChanged
?
- Dumb.
Push and Pull
Push
Updated data is pushed to the observer.
<Observer>.update(data1, data2, ...);
Pull
When data is updated, the observer will manually request data from the subject
<Observer>.update(this);
Java Code
|
|
|
|
|
|
|
|
- Observer can overload its
update
method to function differently, depending on which object has notified it.
Passing functions as observers
Can create an interface which exposes a single method -> SAM - Single Abstract Method.
1 2 3 4 5 6 | addListener(new MyCoolSAM() { @Override int something(int arg1, int arg2) { return arg1 * arg2; } }) |
Could also use a lambda function
1
| addListener((int arg1, String arg2)-> arg1*arg2); |