3

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:

image

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:

image

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).

Community
  • 1
  • 1
artas
  • 116
  • 2
  • 8
  • What's the reason for making desgn GoF-friendly? I don't model to make patterns but use patterns to model where they fit. – qwerty_so Sep 15 '19 at 09:03
  • Yes, sorry, I don't explain the context. Is for an exam in wich is required to apply two pattern to a modelled class diagram. Assuming that the problem is notify the notificationBox of list state change, it's a correct using of observer pattern? – artas Sep 15 '19 at 10:30
  • You must not override `notify` since each instance anyway has its own subscribed observers. – qwerty_so Sep 15 '19 at 15:19
  • But a notify method is something like "for all observer do: observer.update" and I need to modelling the fact that in each subject there is a different subset of observer that should be notified of the change based on specific criterion, and different subject need to call **different update method**. see the example. If I don't override notify how can I modelling the different behaviour of the three subjects? – artas Sep 15 '19 at 16:06
  • Questions about your edit: 1) is it realistic that there will be other SubjectPDC classes than PaginaDiCorso ? 2) Does your NotificationBoxObs really inherit from 3 other classes (multiple inheritance or implementation of multiple interfaces) or is it meant the other way round ? – Christophe Sep 16 '19 at 13:56
  • 1) there will be more than one CoursePage (PaginaDiCorso), one listMDD and one listGS in the system. But for mantaining the pattern structure I made all of this Subject class. 2) Yes in my mind notification box "inherit" ( in practice I think it extends an interface) from each of Observer. what do you think about? – artas Sep 16 '19 at 14:03

2 Answers2

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.

jaco0646
  • 11,033
  • 7
  • 47
  • 64
  • Hi, thank's for answer. Ok so I should break the update method into 3 abstract class that notificationBox extends. But how i handle the notify method, even if each subject have one type of observer it need to decide the subset of its observer that need to be notified, and if I implement the notify method in Subject abstract class i can't handle this, because each subjects use different criterion for select the subset. How can I do? – artas Sep 16 '19 at 07:02
  • Ok I had edit the solution implementing some of your answer! it's more [GoF]-friendly? – artas Sep 16 '19 at 13:04
2

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) ?

Christophe
  • 54,708
  • 5
  • 52
  • 107
  • Me again. The white diamond has no semantics (see p. 110 of UML 2.5). Do not recommend it. – qwerty_so Sep 15 '19 at 19:33
  • @qwerty_so I think we agree. On the same page 110 it is said that "*Sometimes a Property is used to model circumstances in which one instance is used to group together a set of instances; this is called aggregation*". My point was that it's definitely not an exclusive ownership here. As I stated, "*it is preferable to have a simple relation*" (with "simple", I meant neither aggregation nor composite, exactly as you suggest). However I could not exclude the aggregation as a possibility since all the observers of a subject form some kind of group. Should I improve my formulation ? – Christophe Sep 15 '19 at 20:48
  • The box on p. 110 is explicit: _Precise semantics of shared aggregation varies by application area and modeler._ So unless you describe the exact semantics in the domain one should not use it. If you recommend a "simple" association in favor of the aggregation I'd vote up. I think that lots of those (wrongly used) aggregation stem from wrong interpretation of "sub-optimal" definitions in old UML specs. – qwerty_so Sep 15 '19 at 21:28
  • Further, an association with multiplicity is simply enough unless you want to show explicit life time dependency with a composite aggregation. – qwerty_so Sep 15 '19 at 21:33
  • @qwerty_so thanks for the thorough review of the answer. I've updated it. Let me know if it is sufficiently clear now. – Christophe Sep 16 '19 at 06:43
  • Yes! thank's the template method hint is what I search for! thank's!!!! – artas Sep 16 '19 at 07:04
  • Excellent and detailed as always. +1 Anyhow, I think the shared composite is a misconception in UML. What would that be: something between being associate and composite? So that's why I recommend to not use it without definition in the modeling domain, if at all. No need to discuss this further as it would blow up the comment section. – qwerty_so Sep 16 '19 at 07:08
  • The idea behind different updateXXX is: when a subject change state, compute the subset of its observer that need to be notified (now with a hook method in the notify template method) and use the correct update method (using another hook method), for example if the subject is listaMDD it compute the subset and call on each element "o" the method o.updateMDD, the observer on other hand can handle the specific update in correct way. I'm do it right? – artas Sep 16 '19 at 07:31
  • Or maybe I can simplify in this way: insert only one update method in wich each subject pass a string that specify what's happened, so make different behavior by a parameter of update method. In this way for example listaMDD call update("MDD") and the method model the behavior after an MDD is updated. It's better? – artas Sep 16 '19 at 07:42
  • @artas having one update and letting the observer decide what to do, seems to be a better approach. Adding parameters to update() is ok but be aware that the string would hide a coupling. What do you think of passing the subject as parameter of the update() function of the observer ? – Christophe Sep 16 '19 at 11:52
  • @Christophe I had re-designed all the structure. For mantaining notify in broadcast and coupling at low level I had implemented 3 different Subject class, one for each concreteSubject, and 3 Observer class, on for each type of observing. I'll edit the post with this solution, can you tell me if is ok? – artas Sep 16 '19 at 12:58