Closed nicktohzyu closed 3 years ago
The 'observed' object (e.g. StudentList
in the first example) is closely related to the Observer
interface, because the observed object is responsible for managing and notifying the Observer
s whenever something happens to itself.
On the other hand, the 'observing' object can come from any component in the project, as long as it is interested in listening for changes in the observed object. It wouldn't make sense to put Observer
with the observing objects, as they may be scattered across multiple different packages.
The 'observed' object (e.g.
StudentList
in the first example) is closely related to theObserver
interface, because the observed object is responsible for managing and notifying theObserver
s whenever something happens to itself.On the other hand, the 'observing' object can come from any component in the project, as long as it is interested in listening for changes in the observed object. It wouldn't make sense to put
Observer
with the observing objects, as they may be scattered across multiple different packages.
That's correct. The observed are the ones in control. They specify the 'contract' (i.e., the interface) the observers need to follow. If not, the observed becomes dependent on an outside component, which defeats the purpose of the pattern.
I see, in this case might it be more appropriate to call the interface StudentListObserver?
Also, wouldn't the observer need a reference to the observed? Shouldn't this be represented as a solid arrow from observer to observed?
I see, in this case might it be more appropriate to call the interface StudentListObserver?
I suppose that would be a more apt name to make it less ambiguous and more readable, in case there are multiple instances of the observer pattern throughout the project.
Also, wouldn't the observer need a reference to the observed? Shouldn't this be represented as a solid arrow from observer to observed?
The observer does not need a reference to the observed. Once added to the observed, the observer does not need to keep track of anything else as the observed is responsible for updating the observers. Furthermore, the entire purpose of the observer pattern is to eliminate coupling between observer and observed.
If the observer needs to observe some state of the observed the state change can be expressed as a parameter to the update
method in the interface, in which case there may be a dependency from the observer interface. Example: ListChangeListener
and ListChangeListener.Change
@wltan' s answer is correct. Just a clarification about the below:
Furthermore, the entire purpose of the observer pattern is to eliminate coupling between observer and observed.
The pattern eliminates the dependency from the Observed to the Observers. The dependency in the other direction still exists as the new interface in the middle is considered a part of the Observed (but it's not as bad as a direct dependency on the Observed). As @wltan mentioned, the Observers receive all the info they need via the update
method.
the Observers receive all the info they need via the update method
How would this work since the update method is nullary?
As seen in the ListChangeListener
example from JavaFX, the update method (in this case onChanged
) isn't necessarily nullary. If the observer requires additional information, that can be included as part of the interface's dependencies.
As seen in the
ListChangeListener
example from JavaFX, the update method (in this caseonChanged
) isn't necessarily nullary. If the observer requires additional information, that can be included as part of the interface's dependencies.
That's correct. The given example is the simplest possible Observer interface. It can be made more sophisticated as necessary.
The pattern eliminates the dependency from the Observed to the Observers
Hi @damithc . Why does it eliminates the dependency from the Observed to the Observers and not the opposite? If for example taking the code that is in the chapter itself, it is studentList.add(observers)
, isn't this a dependency from the Observed to the Observers?
Hi @damithc . Why does it eliminates the dependency from the Observed to the Observers and not the opposite? If for example taking the code that is in the chapter itself, it is
studentList.add(observers)
, isn't this a dependency from the Observed to the Observers?
studentList.add(observers)
the parameter to this method is the Observer interface (which is provided by the Observed side), not the concrete classes that are doing the actual observing (which are 'outsiders' that the observed doesn't want to depend on). And that makes the difference.
In the example below, it's addUi(Observer)
, not addUi(StudentListUi)
. That means the StudentList
(i.e., the observed) doesn't know anything about the outside observers (e.g., StudentListUi
) and yet it can inform those observers when the data changes.
This point is also explained in the lecture video here https://nus-cs2103-ay2021s1.github.io/website/schedule/week11/topics.html#design-design-patterns-observer-pattern-what
As seen in the
ListChangeListener
example from JavaFX, the update method (in this caseonChanged
) isn't necessarily nullary. If the observer requires additional information, that can be included as part of the interface's dependencies.
Thanks, I understand this part, since information is passed as Change
into the method. What i'm wondering about is whether a nullary update
would work?
Thanks, I understand this part, since information is passed as
Change
into the method. What i'm wondering about is whether a nullaryupdate
would work?
In some cases, the observer just need to know something changed, not necessarily what changed e.g., to invalidate a cache. In such cases, no need to send state info via a parameter.
thanks!
Example from textbook
Example from AY14/15S2 paper
In both these cases, it seems that the interface is grouped with the class to be observed (data/students) rather than the observer. why is this the case? I would instinctively group it with either the observer, or put the interface outside of a grouping