Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "OTExample Observer/ObservingOpen"

(New page: '''Application of the Observer pattern''' This team binds the ObserverPattern: * The Subject role is played by Flower ...)
 
Line 1: Line 1:
'''Application of the Observer pattern'''
+
===Application of the Observer pattern===
  
 
This team binds the [[OTExample Observer/ObserverPattern|ObserverPattern]]:
 
This team binds the [[OTExample Observer/ObserverPattern|ObserverPattern]]:
Line 17: Line 17:
 
public team class ObservingOpen extends ObserverPattern {
 
public team class ObservingOpen extends ObserverPattern {
  
 +
    @Override
 
     protected class Subject playedBy Flower
 
     protected class Subject playedBy Flower
 
     {
 
     {
Line 55: Line 56:
 
</source>
 
</source>
  
'''Explanation:'''
+
===Explanation===
''soon''
+
Applying the pattern happens in 4+1 steps involving: (1) teams, (2) roles, (3) callout bindings and (4) callin bindings. Additionally registration methods are provided for defining at runtime which instances should participate in this pattern.
 +
 
 +
====Team Specialization====
 +
Applying the generic pattern is implemented by sub-classing the '''team''' ''ObserverPattern''.
 +
 
 +
====Role Specialization and Binding====
 +
The roles of the pattern are specialized using two slightly different mechanisms: '''roles''' ''BeeObserver'' and ''HummingbirdObserver'' use regular inheritance (extends) for specialization and bind using '''playedBy''' to one existing base class each.
 +
 
 +
Role ''Subject'' on the other hand uses implicit inheritance, which is a combination of '''overriding''' the inherited abstract class ''Subject'' and also '''implicitly inheriting''' from the class being overridden. Thus implicit inheritance ({{otjld|1|.3.1}}) can be understood as continuing with the inherited definition of class ''Subject''. Similar to the two previous roles also ''Subject'' is bound to a base class using playedBy.
 +
 
 +
====Callout bindings====
 +
The missing action implementation of both specialized ''Observer'' roles is bound using callout ({{otjld|3|}}), as seen in lines 25 and 29. By these bindings the ''update(Subject)'' method is no longer abstract.
 +
 
 +
====Callin bindings====
 +
Binding a trigger for ''changeOp()'' is basically as simple as the above callout bindings. The '''callin''' binding in line 21 defines that whenever method ''open()'' is called on a ''Flower'', the notification should be triggered before the regular behaviour. However, In order to observe only ''open()'' calls that actually have an effect, method ''changeOp()'' is refined so that the notification mechanisms will only be called if the ''Flower'' was not already open.
 +
 
 +
Here the expression ''isOpen'' demonstrates one way how a role can access state of its base: we let the compiler implicitly '''infer''' a '''callout''' accessor to the given base class field ({{otjld|3|.5.h}}). Callout inference has to be enabled by a compiler preference and if configured as warnings the compiler urges the developer to document the use of inferred callouts by saying ''@SuppressWarnings("inferredcallout")''.
 +
 
 +
Additionally, method ''changeOp()'' demonstrates how to invoke the super method in case of implicit inheritance: by using '''tsuper''' instead of '''super''' we denote that a same-named class from the super-team should be searched for the method ({{otjld|1|.3.1.f}}).
 +
 
 +
====Registration methods====
 +
The three methods defined at the team level (lines 32-45) provide a facade for the add/remove methods of class ''Subject''.
 +
 
 +
Method ''removeAllObserversFromSubject(Flower '''as''' Subject subject)'' expects a ''Flower'' instance as its argument but before entering the method body this instance is '''lifted''' to its ''Subject'' role ({{otjld|2|.3.2}}). If lifting finds no matching role for this ''Flower'' a new role instance is created implicitly.
 +
 
 +
For the other two methods signatures are a bit more advanced. The intention is to define a method that receives a ''Flower'' (as the ''Subject'') and either a ''Bee'' or a ''Hummingbird'' (as the ''Observer'').
 +
Since ''Bee'' and ''Hummingbird'' have no common supertype (aside from useless ''Object'') the method is declared generically by introducing a type parameter ''AnyBase''. Now a free type parameter would be too weak (just like specifying ''Object'' would be). So we constrain the type parameter to only those classes that are a base class of role ''Observer''. This is a precise definition of the set {''Bee'',''Hummingbird''} (taking into account that the sub-classes ''BeeObserver'' and ''HummingbirdObserver'' are conform to the type bound ''Observer''). By declaring ''<AnyBase '''base''' Observer>'' we say that ''AnyBase'' can stand for any type that is '''liftable''' to ''Observer''. This capability is used by actually requesting this lifting in ''AnyBase '''as''' Observer observer''. See the [[OTExample Observer/Main|Main]] class for applications of these methods.
 +
 
 +
 
 +
This concludes the application of the ''ObserverPattern'' for observers interested in when a ''Flower'' ''opens''. Note, how little coding is actually required since most tasks are performed by declarative bindings.

Revision as of 04:52, 24 February 2010

Application of the Observer pattern

This team binds the ObserverPattern:

A few comments are given inline, for more explanation see below.

  1. package flower_example;
  2.  
  3. import protocol.ObserverPattern;
  4. /**
  5.  * @author Bruce Eckel (original Java example)
  6.  * @author Miguel P. Monteiro (adaptation to OT/J)
  7.  */
  8. public team class ObservingOpen extends ObserverPattern {
  9.  
  10.     @Override
  11.     protected class Subject playedBy Flower
  12.     {
  13.         // This method  implicitly uses a private field of its base class: isOpen
  14.         @Override
  15.         @SuppressWarnings({ "inferredcallout", "decapsulation" })
  16.         public void changeOp() {
  17.             // manual implementation, see ObservingClose.Subject for an abbreviation.
  18.             if(!isOpen)
  19.                 tsuper.changeOp();
  20.         }
  21.         changeOp <- before open;
  22.     }
  23.  
  24.     public class BeeObserver extends Observer playedBy Bee {
  25.         update -> haveBreakfast;
  26.     }
  27.  
  28.     public class HummingbirdObserver extends Observer playedBy Hummingbird {
  29.         update -> breakfastTime;
  30.     }
  31.  
  32.     // This and the following signature applies OTJLD §2.3.2(e):
  33.     public <AnyBase base Observer>
  34.     void mapSubject2Observer(Flower as Subject subject, AnyBase as Observer observer) {
  35.         subject.addObserver(observer);
  36.     }
  37.  
  38.     public <AnyBase base Observer>
  39.     void removeObserverFromSubject(Flower as Subject subject, AnyBase as Observer observer) {
  40.         subject.removeObserver(observer);
  41.     }
  42.  
  43.     public void removeAllObserversFromSubject(Flower as Subject subject) {
  44.         subject.removeAllObservers();
  45.     }
  46. }

Explanation

Applying the pattern happens in 4+1 steps involving: (1) teams, (2) roles, (3) callout bindings and (4) callin bindings. Additionally registration methods are provided for defining at runtime which instances should participate in this pattern.

Team Specialization

Applying the generic pattern is implemented by sub-classing the team ObserverPattern.

Role Specialization and Binding

The roles of the pattern are specialized using two slightly different mechanisms: roles BeeObserver and HummingbirdObserver use regular inheritance (extends) for specialization and bind using playedBy to one existing base class each.

Role Subject on the other hand uses implicit inheritance, which is a combination of overriding the inherited abstract class Subject and also implicitly inheriting from the class being overridden. Thus implicit inheritance (OTJLD §1.3.1) can be understood as continuing with the inherited definition of class Subject. Similar to the two previous roles also Subject is bound to a base class using playedBy.

Callout bindings

The missing action implementation of both specialized Observer roles is bound using callout (OTJLD §3), as seen in lines 25 and 29. By these bindings the update(Subject) method is no longer abstract.

Callin bindings

Binding a trigger for changeOp() is basically as simple as the above callout bindings. The callin binding in line 21 defines that whenever method open() is called on a Flower, the notification should be triggered before the regular behaviour. However, In order to observe only open() calls that actually have an effect, method changeOp() is refined so that the notification mechanisms will only be called if the Flower was not already open.

Here the expression isOpen demonstrates one way how a role can access state of its base: we let the compiler implicitly infer a callout accessor to the given base class field (OTJLD §3.5.h). Callout inference has to be enabled by a compiler preference and if configured as warnings the compiler urges the developer to document the use of inferred callouts by saying @SuppressWarnings("inferredcallout").

Additionally, method changeOp() demonstrates how to invoke the super method in case of implicit inheritance: by using tsuper instead of super we denote that a same-named class from the super-team should be searched for the method (OTJLD §1.3.1.f).

Registration methods

The three methods defined at the team level (lines 32-45) provide a facade for the add/remove methods of class Subject.

Method removeAllObserversFromSubject(Flower as Subject subject) expects a Flower instance as its argument but before entering the method body this instance is lifted to its Subject role (OTJLD §2.3.2). If lifting finds no matching role for this Flower a new role instance is created implicitly.

For the other two methods signatures are a bit more advanced. The intention is to define a method that receives a Flower (as the Subject) and either a Bee or a Hummingbird (as the Observer). Since Bee and Hummingbird have no common supertype (aside from useless Object) the method is declared generically by introducing a type parameter AnyBase. Now a free type parameter would be too weak (just like specifying Object would be). So we constrain the type parameter to only those classes that are a base class of role Observer. This is a precise definition of the set {Bee,Hummingbird} (taking into account that the sub-classes BeeObserver and HummingbirdObserver are conform to the type bound Observer). By declaring <AnyBase base Observer> we say that AnyBase can stand for any type that is liftable to Observer. This capability is used by actually requesting this lifting in AnyBase as Observer observer. See the Main class for applications of these methods.


This concludes the application of the ObserverPattern for observers interested in when a Flower opens. Note, how little coding is actually required since most tasks are performed by declarative bindings.

Back to the top