问题
I'm modelling a situation in wich there are:
- NotificationBox: the observer
- list1, list2, list3: the subjects
now I would make a piece of diagram in wich using observer pattern describe the fact that each list implement different type of notify() (for example some change in the state of a list need to be notified only to some observer, with some criterion)
I made something like:
in this case each subject override the notify method in order to notify only some subset of observer depend on some criterion, and for using the correct update method.
Example
ListaMDDpubblico is a list composed by some file, each file have a specific tag. When a file is loaded, only the notificationBox associated at the user that "like" the tag of the file should be notified by using updateMDD.
It is [GoF]-friendly?
Or I need to make 3 different Subject abstract class, each implement the notify method in the list-way?
Thank's in advance
[EDIT]
After some reasoning on the answer and comment, another possible design of this situation that I made is:
In this way each change is notify at all subscribed observer (for each different type of subject) and logic to understand if the notification must be taken into consideration is modeled in the update methods implemented by the notificationBox (so the notification now is broadcast and each ConcreteSubject don't need to know nothing about concreteObserver).
回答1:
Comparison of your observer with the GoF pattern
In the GoF observer, notify()
is implemented in the abstract Subject
: the update()
function of all observers are called, up to them to decide if the object-update notification is relevant or not. In this way, the subject does not have to know anything specific about the observers.
First potential design issue
If you let Subject
decide which Observer
to notify, the subject might need to know additional details about the observer. Depending on what the subject needs to know about the observer for its decision making, this may or may not be ok:
- If the concrete subjects need to know about the concrete observers, the design would increase the coupling in a way that is not desirable. In fact, this goes against the open/close principle, since adding new kind of observers would require to adjust the concrete subjects. Maintenance nightmare in sight !
- If concrete subjects only need to know the interface of the abstract observer, your design would be ok. In the spirit of DRY I'd nevertheless suggest to combine this pattern with the template method pattern, to let the
notify()
be general, and make it dependent on an abstract condition that can change according to the concrete subject.
Second potential design issue
It seems that your concrete observers need to know the type of the subject in order to call the right update function. I'm not sure that it's really the case, but it's the impression coming your naming convention of updateXXX()
, because each XXX
is used in ony one subject.
If this is the case, the Observer
abstraction would depend on concrete implementation of Subject
. This does not seem a good idea: concrete classes may depend on abstract classes, but the contrary is against the open/close principle.
UML modelling issues
On the UML diagram, I would advise not to use the black composition diamond from Subject
to Observer
:
- composite (black diamond) means that the observers belong exclusively to the subject (i.e. if the subject is deleted, its observers would not survive). I doubt that it's the case here.
- aggregate (white diamond) would have a similar meaning but with a shared ownership (not exclusive). I cannot exclude this, but I see no compelling argument to use it here either.
- I would recommend a simple (one-to-many) association.
- If you leave the multiplicity of 1 on the side of the subject, your observer would have to register during its construction. Is it what you intend to implement, or should it be 0..1 ?
The navigable association from concrete observer to all the concrete subjects raises questions:
- is there a navigable association between the concrete observer and abstract subject ? (in this case draw the association with the abstract class, in order to be accurate)
- or are there 3 navigable associations: between the concrete observer and each of the concrete subjects ?
Think about the open/close principle in this regard. What would you expect to happen if you'd need to add a new concrete subject ? Would you have to change all the concrete observers (adding a new association) ? Or would you expect it to work without any change (because the association is with the abstract subject) ?
回答2:
The GoF book addresses this issue in detail on pages 298-299. I think the design shown above is closest to,
Specifying modifications of interest explicitly. You can improve update efficiency by extending the subject's registration interface to allow registering observers only for specific events of interest. When such an event occurs, the subject informs only those observers that have registered interest in that event.
The GoF book implements this a bit differently from the design shown above, however. The above design expands the observer interface to specify each type of event, so knowledge of event types spreads to each subject (and each observer, if there is more than one). Furthermore, if new event types are added in the future, the temptation will be to edit the observer interface.
For these reasons, I prefer an approach utilizing multiple observers. Rather than combining all update methods into one interface, separate them into GsObserver
, MddObserver
, and DdlObserver
. Each subject is capable of registering only one of these observer interfaces, but the NotificationBox
can implement all three.
来源:https://stackoverflow.com/questions/57941730/can-a-gof-concretesubject-override-the-notify-method