Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

PlantUML Macro
class CD {
	int getTrackCount()
	Track getTrack(int)
	void addTrack(Track)
	void removeTrack(Track)
}
class Track {
}
CD --> "*" Track: tracks
Code Block
languagejava
public class CD {

    private List<Track> tracks = new ArrayList<Track>();
    
    public int getTrackCount() {
        return tracks.size();
    }

    public Track getTrack(int index) {
        return tracks.get(index);
    }
    
    public void addTrack(Track track) {
        if (! tracks.contains(track)) {
	        tracks.add(track);
		}
    }

    public void removeTrack(Track track) {
        tracks.remove(track);
    }
}

Klassediagrammet og koden til venstre viser hvordan tracks-assosiasjonen er realisert. Vi ser at tracks-assosiasjonen den er kapslet inn med en rekke metoder og at realiseringen bruker en intern ArrayList. Alle innkapslingsmetodene kaller bare tilsvarende metoder i ArrayList-objektet, uten noe særlig mer logikk. Vi sier at CD delegerer til ArrayList. Sekvensdiagrammet til høyre illustrerer hvordan det CD-objektet bruker ArrayList-objektet.

Selv om vi hadde lagt til litt validering og annen logikk, så hadde alt grovarbeidet i praksis blitt utført av ArrayList-klassen, og uten mulighet til å delegere og dermed (gjen)bruke logikken i ArrayList-klassen, så ville CD-klassen blitt mye mer kompleks.

Dette er typisk for delegeringsteknikken:

  • Den delegerende klassen har et internt objekt av delegat-klassen, altså objektet som det delegeres til, som gjør det meste av grovarbeidet.
  • Den delegerende klassen har metoder med samme eller lignende navn som delegat-klassen.
  • Disse metodene delegerer mer eller mindre direkte til delegat-objektet.

Hvis en tegner hva som skjer i et sekvensdiagram så blir delegeringen åpenbar:Sekvensdiagrammet illustrerer den generelle teknikken godt, bare bytt ut CD med delegerende og ArrayList med delegat.

PlantUML Macro
Hovedprogram --> CD: getTrackCount
CD --> "tracks: ArrayList": size
Hovedprogram --> CD: getTrack
CD --> "tracks: ArrayList": get
Hovedprogram --> CD: addTrack
CD --> "tracks: ArrayList": contains
CD --> "tracks: ArrayList": add
Hovedprogram --> CD: removeTrack
CD --> "tracks: ArrayList": remove

I dette tilfellet er det faktum at en bruker delegering ikke på noen måte synlig utenifra, fordi det ArrayList-objektet opprettes internt i klassen og det gis ingen direkte tilgangen til det, siden det jo er kapslet inn. Men i mange tilfeller er litt av poenget at en utenifra kan styre hvilket objekt det delegeres til og dermed påvirke totaloppførselen. Dette illustreres av følgende eksempel.

Vi skal lage en iterator som går gjennom (genererer) annenhvert element i en liste, men istedenfor å knytte den direkte til en List (eller Collection/Iterable), så lar vi den delegere til en annen iterator:

PlantUML Macro
class EverySecondIterator implements Iterator<Object> {
	Iterator<Object> iteratorDelegate
	EverySecondIterator(Iterator<Object>)
	boolean hasNext()
	Object next()
}
interface "Iterator<Object>" as iterator {
}
EverySecondIterator --> iterator: iteratorDelegate
Code Block
languagejava
public class EverySecondIterator implements Iterator<Object> {
	
	private Iterator<Object> iteratorDelegate;
    
    public EverySecondIterator(Iterator<Object> iterator) {
        this.iteratorDelegate = iterator;
    }
    
    @Override
    public boolean hasNext() {
        return iteratorDelegate.hasNext();
    }

	@Override
    public Object next() {
        Object o = iteratorDelegate.next();
        if (iteratorDelegate.hasNext()) {
            iteratorDelegate.next();
        }
        return o;
    }
}
Vi ser at hvert kall til hasNext() vil resultere i et kall til hasNext()delegaten (iteratorDelegate). Hvert kall vil next() vil imidlertid gi først et kall til next()delgaten og så et kall til hasNext() og evt. et nytt kall til next().
PlantUML Macro
Hovedprogram --> EverySecondIterator: hasNext()
EverySecondIterator --> "iteratorDelegate: Iterator<Object>": hasNext()
Hovedprogram --> EverySecondIterator: next()
EverySecondIterator --> "iteratorDelegate: Iterator<Object>": next()
EverySecondIterator --> "iteratorDelegate: Iterator<Object>": hasNext()
EverySecondIterator --> "iteratorDelegate: Iterator<Object>": next()