Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3

...

n-n-assosiasjoner er koblinger mellom objekter hvor ett objekt av en type kan ha flere av en navngitt kobling til andre objekter av en annen eller samme type, og disse objektene også har en kobling tilbake men kan også ha flere koblinger til andre objekter. Et eksempel er at et emne kan undervises av flere personer, og at en person kan undervise i flere fag. Et Person-objekt kan altså ha ingen, én eller flere foreleser-koblinger til Emne-objekter, mens et Emne-objekt kan ha en eller flere forelest av-koblinger til Person-objekter.

n-n-assosiasjoner kodes i Java med et Collection-felt spesialisert med < > til riktig type og med navn tilsvarende rollen (gjerne i flertall). Navngivingen av feltet er forsåvidt underordnet, siden det er innkapslingen i form av bl.a. add og remove-metoder som er viktig. Her er diagrammet for en generell n-n-assosiasjon og kode-malen for de to klassene som deltar i den:

PlantUML Macro
class 

...

Rolle1Klasse {
}
class 

...

Rolle2Klasse {
}

...

Rolle1Klasse "

...

rolle1 

...

0:n" -- "

...

rolle2 0:n" 

...

Rolle2Klasse: assosiasjon


Code Block
languagejava
public class Rolle1Klasse {

	private Collection<Rolle2Klasse> roller2 = new ArrayList<Rolle2Klasse>();

	public void addRolle2(Rolle2Klasse rolle2) {
		// unngå duplikat
		if (! roller2.contains(rolle2)) {
			this.roller2.add(rolle2);
		}
	}

	public void removeRolle2(Rolle2Klasse rolle2) {
		this.roller2.remove(rolle2);
	}
}
 
public boolean hasRolle2(Rolle2Klasse rolle2){
	return this.roller2.contains(rolle2);
}
Code Block
languagejava
public class Rolle2Klasse {

	private Collection<Rolle1Klasse> roller1 = new ArrayList<Rolle1Klasse>();

	public void addRolle1(Rolle1Klasse rolle1) {
		// unngå duplikat
		if (! roller1.contains(rolle1)) {
			this.roller1.add(rolle1);
		}
	}

	public void removeRolle1(Rolle1Klasse rolle1) {
		this.roller1.remove(rolle1);
	}
}
 
public boolean hasRolle1(Rolle1Klasse rolle1){
	return this.roller1.contains(rolle1);
}

For å sette opp en gjensidig kobling, så må en opprette en eller flere av den ene typen og en eller flere av den andre og kalle add-metoder med objekt av den andre typen som argument:

PlantUML Macro
object "r21 : Rolle2Klasse" as r21 {
}
object "r11 : Rolle1Klasse" as r11 {
}
object "r22 : Rolle2Klasse" as r22 {
}
object "r12 : Rolle1Klasse" as r12 {
}




r11 -right-> "rolle2" r21
r12 -right-> "rolle2" r21
r11 --> "rolle2" r22
r12 --> "rolle2" r22
r21 --> "rolle1" r11
r22 --> "rolle1" r11
r21 --> "rolle1" r12
r22 --> "rolle1" r12






Code Block
languagejava
Rolle1Klasse r11 = new Rolle1Klasse(), r12 = new Rolle1Klasse;
Rolle2Klasse r21 = new Rolle2Klasse(), r22 = new Rolle2Klasse();
// koblinger den ene veien
r11.addRolle2(r21);
r11.addRolle2(r22);
r12.addRolle2(r21);
r12.addRolle2(r22);
// og den andre veien
r21.addRolle1(r11);
r22.addRolle1(r11);
r21.addRolle1(r12);
r22.addRolle1(r12);

Med koden i klassene over, så må en altså selv sørge for konsistens, dvs. at hvis r11 er koblet til r21 og r22 gjennom rolle2, så er r21 og r22 koblet til r11 gjennom rolle1. Det er bedre om dette skjer automatisk, så en er sikret konsistens. Merk at dette bare gjelder når assosiasjonen er to-veis, noe den ikke alltid er.

Det skal altså være nok å kalle add-metoden for å sette opp begge koblingene (evt. koble begge av med removeRolleX). add- og remove-metodene må derfor sjekke koblingen den andre veien, også. Dette kan være litt fiklete å gjøre rett, så her er koden for add-metoden for Rolle1Klasse, som vil være tilsvarende for Rolle2Klasse:

Code Block
// i Rolle1Klasse

public void addRolle2(Rolle2Klasse rolle2) {
	// sjekk om koblingen er riktig allerede
	if (this.roller2.contains(rolle2)) {
		return;
	}
	this.roller2.add(rolle2);
	// opprett koblingen tilbake, om nødvendig
	if (! rolle2.hasRolle1(this)) {
		rolle2.addRolle1(this);
	}
}

public void removeRolle2(Rolle2Klasse rolle2) {
	// sjekk om koblingen er riktig allerede
	if (! this.roller2.contains(rolle2)) {
		return;
	}
	this.roller2.remove(rolle2);
	// fjern koblingen tilbake, om nødvendig
	if (rolle2.hasRolle1(this)) {
		rolle2.removeRolle1(this);
	}
}

 

 

add- og remove-metodene sørger dermed for å gjøre tilstanden konsistent. Merk at innkapslingen er ivaretatt ved at en klasse bruker innkapslingsmetoder hos den andre.