Een aspect van het Observer patroon

 
02 januari 2009

Ik wil hier graag een aspect van het Observer-patroon bespreken. Het Observer-patroon bespreekt hoe een object kan aangeven dat het veranderd is, zonder harde koppelingen te maken. In het boek “Design Patterns” van de Gang of Four (GoF) wordt een aanvulling besproken. Het behandelt de situatie, dat een Observer alleen geïnteresseerd is in een bepaald aspect van een verandering. In deze post geef ik mijn interpretatie hiervan.

In Domain Driven Design staat het model centraal. Het model mag services er omheen niet kennen. Het model kan services op de hoogte houden van toestandveranderingen door middel van events. Een manier om events te implementeren is door het Observer-patroon to te passen. In het huidige project waaraan ik werk, kwamen we voor deze situatie te staan.

We ondervonden daarbij het volgende probleem: Het kan voorkomen dat een Observer alleen geïnteresseerd is in een bepaald aspect van een toestandsverandering van een object. Stel je een effectenmakelaar voor. Deze makelaar handelt in een aandeel en wil op de hoogte gesteld worden van de waardeverandering. Maar hij is alleen maar geïnteresseerd als het aandeel in waarde daalt. De effectenmakelaar kan dan beslissen het aandeel te verkopen.

Het is niet wenselijk om voor ieder aspect een aparte registreermethode te hebben, ala
...
AddWaardeVerhoogdObserver
AddWaardeVerlaagdObserver
....

Deze methoden zullen veel op elkaar lijken. Het is verstandig het aspect te abstraheren. Dit idee wordt al besproken door de GoF. In de opmerking paragraaf bespreken zij de toevoeging van aspecten. In de rest van deze post bespreek ik mijn interpertaties van deze opmerking.

Aspecten

Hieronder staat het UML diagram van het Observer-patroon met aspecten. Het originele patroon is duidelijk herkenbaar. Eén van de veranderingen is de toevoeging van een Aspect-klasse. Hierdoor is het voor een Observer mogelijk te concentreren op een interessante verandering. Mijn interpertatie van aspecten is als volgt.

Het klasse diagram van het Observer patroon

Het klasse diagram van het Observer patroon

Een aspect komt zelf voor binnen een hiërarchie van aspecten. Sommige aspecten zijn specifieker dan andere. Denk nog even terug aan onze effectenmakelaar. De aspecten aan een aandeel zijn bijvoorbeeld waarde veranderd, waarde gestegen en waarde gedaald. De laatste twee zijn specifiekere veranderingen van het eerste type. Ik heb er dan ook voor gekozen om aspecten als klassen elkaar te laten overerven.

Dit gebruik ik in de notifyObserver(Aspect) methode:

public void notifyObservers(Aspect aspect) {
 
  if (aspect != null) {
 
    if (aspectToObservers.containsKey(aspect)) {
 
      for (Observer observer: aspectToObservers.get(aspect)) {
 
        observer.update(this, aspect);
 
      }
 
    }
 
    notifyObservers(aspect.getAParent());
 
  }
 
}

Hieraan zie je dat niet alleen Observers van het huidige aspect op de hoogte worden gesteld. Ook van het superklasse van het huidige aspect. De methode getAParent() van Aspect staat hieronder. Er wordt met reflectie een instantie van een superklasse gemaakt als deze de Aspect-interface implementeert.

public Aspect getAParent() {
 
  Aspect parent = null;
 
  Class baseClass = this.getClass();
 
  Class superClass = baseClass.getSuperclass();
 
  if (superClass != null) {
 
    Class[] superInterfaces = superClass.getInterfaces();
 
    for (Class superInterface: superInterfaces) {
 
      if (superInterface.equals(Aspect.class)) {
 
        try {
 
          parent = (Aspect) superClass.newInstance();
 
        } catch (InstantiationException e) {
 
          assert false;
 
        } catch (IllegalAccessException e) {
 
          assert false;
 
        }
 
      }
 
    }
 
  }
 
  return parent;
 
}

Aspecten geven toestandsveranderingen in het model aan. Observers kunnen specifieke aspecten observeren. Het gedrag van een Observer is geabstraheerd in een Handler. Een handler is in de regel zeer object-specifiek. Een specifiek object observeert een ander specifiek object. Ik vind het dan ook gelegitimeerd om in de handlers observer en subject naar hun werkelijke type te casten.
Om de werking van bovenstaande code te illustreren heb ik een voorbeeld geimplementeerd.

Voorbeeld
In dit voorbeeld is er een moeder met kinderen. Kinderen zijn in een bepaalde stemming en hebben een bepaalde afstand tot hun moeder. Kinderen laten hun moeder van hun toestandsveranderingen weten. Hieronder vind je het klasse-diagram van de aspecten. De kinderen laten moeder alleen van de meest specifieke veranderingen weten.

De aspecten van een Kind.

De aspecten van een Kind.

Alles is terug te vinden in mee geleverde jar file. Het kan worden uitgevoerd met observerPatternExample.jar. De source bestanden zijn ook ingepakt. Zo heb ik er voor gekozen om de verantwoordelijkheid van het implementeren van de interfaces te delegeren. Zo hoeft maar een keer een implementatie geschreven te worden.


Werken met ?
Kijk dan bij onze mogelijkheden voor starters en/of ervaren IT'ers.


Categorieën: Development

Tags: , ,


Trackback & Pingback (1)

  1. Van Wat is het domein? | Software Innovators op 16 januari 2009 at 11:08

    […] De methodes op het object (in dit geval is het een object en geen class) moeten daadwerkelijk uitgevoerd kunnen worden, bijvoorbeeld door een popup menu op het gevisualiseerde object. De applicatie waarvoor de discussie ontstaat “wat is het domein?” is deze hulpapplicatie voor VisualStudio, waarin visualisaties als hierboven getoond mogelijk moeten zijn (voor de VisualStudio experts: het betreft een soort Object Bench). Is het Risico object het domein? Dit ligt het meest voor de hand, immers de illustratie lijkt een soort user interface te zijn voor dit domein object. Toch leidt deze benadering tot problemen en discussies. Bijvoorbeeld voor het visualiseren van meerdere van dit soort domein objecten is het nodig de ontstane object graaf te bewaren en voor een volgende xM sessie weer “op te brengen”. Hiervoor moet bijvoorbeeld de layout van de objecten worden bewaard. Een wezenlijker probleem is het opvragen met een popup menu van een methode van een domein object. Dit is niet iets dat typisch behoort tot het domein van de eindgebruiker, maar iets dat wel degelijk behoort tot het “domein” van deze applicatie. Kortom, het lijkt erop aan te sturen dat voor dit soort applicaties een soort van “tussendomein” nodig is. Dit is precies wat hier aan de hand is. Rondom de “echte” domein objecten als Risico en Dekking moeten wrappers worden geplaatst, en deze gewrapte objecten functioneren als de domein objecten voor onze applicatie. Ik liep voor het eerst tegen dit pattern aan bij het ontwikkelen van SmallSim, één van mijn eerste projecten. Dit systeem biedt een platform aan voor het modelleren van complexe systemen, die vervolgens ook kunnen executeren – executable modellen kortom. Hierbij zijn ook de werkelijke domein objecten gewrapt. Het is belangrijk zich te realiseren dat deze gewrapte objecten, die de domein objecten zijn voor de applicatie, niet direct hetzelfde zijn als wrappers of adapters zoals we die normaal maken om domein objecten te koppelen met techniek (bijvoorbeeld Aspect Adapters). […]