# Wie Assoziationen implementieren in Java



## ernst (5. Apr 2010)

Hallo allerseits,
In Java kann man Assoziationen realisieren, indem man das Objekt, auf das gezeigt wird, als Attribut in eine Klasse aufnimmt.
Es gibt folgende Assoziationen:
1 : 1
1 : n

Frage:
Gibt es auch n : m Assoziationen.
Wie werden diese programmtechnisch realisiert?

mfg
Ernst


----------



## musiKk (5. Apr 2010)

Naja, wenn eine Klasse A eine Collection, also z. B. eine List oder ein Set mit Elementen einer Klasse B hat, dann ist das ja potentiell schon eine m:n Beziehung, da mehrere A-Objekte auf die gleichen B-Objekte verweisen können.


----------



## Final_Striker (5. Apr 2010)

Ich würde mal sagen:

Klasse A hat eine Liste von Referenzen auf Klasse B
Klasse B hat eine Liste von Referenzen auf Klasse A

müsste dann doch eine n:m Beziehung sein.


----------



## Der Müde Joe (5. Apr 2010)

1:1 tönt nach referenz
1:n tönt nach list bzw array


----------



## ernst (7. Apr 2010)

Final_Striker hat gesagt.:


> Ich würde mal sagen:
> 
> Klasse A hat eine Liste von Referenzen auf Klasse B
> Klasse B hat eine Liste von Referenzen auf Klasse A
> ...



Und wo werden die Verlinkungen gemacht?
Im Konstruktor ?
Wie ?

mfg
Ernst


----------



## HoaX (7. Apr 2010)

Überleg doch mal wie es mit ner 1:n geht, das kannst du doch zu 99% übernehmen ...


----------



## Final_Striker (8. Apr 2010)

ernst hat gesagt.:


> Und wo werden die Verlinkungen gemacht?
> Im Konstruktor ?
> Wie ?
> 
> ...



Du kannst die Listen im Konstruktor übergeben. Kannst aber genau so gut, Get- und Setmethoden schreiben.


----------



## ernst (8. Apr 2010)

Final_Striker hat gesagt.:


> Du kannst die Listen im Konstruktor übergeben. Kannst aber genau so gut, Get- und Setmethoden schreiben.


Bei einer 1 zu 1 Assoziation wird in einem Konstruktor als Parameter this verwendet (falls Objekt im Konstruktor erstellt wird).
Wird das gleiche Schema auch bei n zu m Assoziationen gemacht?

mfg
Ernst


----------



## Wortraum (11. Apr 2010)

Es gibt in dem Sinne kein Schema. Eine Assoziation ist ja nichts anderes als eine Variable mit einer Referenz auf ein anderes Objekt.

```
public class Autohaus {
    private List<Auto> vieleAssoziationen;

    public void setAutos(List<Auto> autos) {
        vieleAssoziationen = autos;
    }
```

Sollen die Autos auch noch das Autohaus-Objekt kennen, muß man es ihnen natürlich übergeben. Das kann beispielsweise schon bei der Erzeugung eines Autos geschehen oder kann später an anderer Stelle oder aber auch innerhalb von setAutos(List<Auto>) gemacht werden.

```
public void setAutos(List<Auto> autos) {
    vieleAssoziationen = autos;
    for (Auto a : autos) {
        a.setAutohaus(this);
    }
}
```

Oder beispielsweise „außerhalb“ des Autohauses:

```
public static void main(String[] args) {
    Autohaus autohaus = new Autohaus();
    List<Auto> autos = new ArrayList<Auto>();
    for (int i = 0; i < 10; ++i) {
        autos.add(new Auto(autohaus));
    }
}
```

Jedes Auto kennt hier nun das Autohaus. Jedes Autohaus kann nun selbst dem Autohaus „Bescheid geben“, daß es zu ihm gehört, oder es könnte unter der Schleife mit autohaus.setAutos(autos) gemacht werden. Es ist für eine Assoziation ziemlich egal, wie die Objekte voneinander erfahren.

Natürlich könnte man Auto auch so programmieren, daß man ihm mehrere Autohäuser übergeben kann (beispielsweise wieder eine Liste mit Autohäusern übergeben), und schon hätte man eine n:m-Beziehung.


----------



## ernst (12. Apr 2010)

Wortraum hat gesagt.:


> Es gibt in dem Sinne kein Schema. Eine Assoziation ist ja nichts anderes als eine Variable mit einer Referenz auf ein anderes Objekt.


Das folgende Beispiel beschreibt eine bidirektionale Assoziation zwischen Autos und Fahrer:
Zu einem Auto gehören 2 Fahrer und 
ein Fahrer fährt 3 Autos.
Konkret:
a1 --- f1
a1 --- f2
a2 --- f1
a2 --- f2
a3 --- f1
a3 --- f2

1) Version1
In meiner 1. Version werden die Verlinkungen alle (außerhalb) in main gemacht.
Allerdings gibt es da eine Redundanz:
Wenn ich eine Assoziation, wie z.B:
a1 --> {f1, f2}
realisiert habe, muß in der Liste, die f1 zugewiesen wird, logischerweise a1 enthalten sein ("Rückverlinkung").
Dies passiert bei meiner 1. Version nicht automatisch, sondern dies impliziert die folgende Anweisung:
FahrerLink fl1 = new FahrerLink(f1, autos);

```
package assoziationbi_nzum_1;

public class MainAssoziationBI_NzuM_1 {
	public static void main(String[] args){

        /* Zu realsisierende Verlinkungen:
        a1 --- f1
        a1 --- f2
        a2 --- f1
        a2 --- f2
        a3 --- f1
        a3 --- f2
        */

        Auto a1 = new Auto("A1");
        Auto a2 = new Auto("A2");
        Auto a3 = new Auto("A3");

        Fahrer f1 = new Fahrer("F1-Alice");
        Fahrer f2 = new Fahrer("F2-Berta");

        Auto[] autos = new Auto[3];
        autos[0]=a1;
        autos[1]=a2;
        autos[2]=a3;
        Fahrer[] fahrer = new Fahrer[2];
        fahrer[0] = f1;
        fahrer[1] = f2;

        AutoLink al1 = new AutoLink(a1, fahrer);
        AutoLink al2 = new AutoLink(a2, fahrer);
        AutoLink al3 = new AutoLink(a3, fahrer);
        FahrerLink fl1 = new FahrerLink(f1, autos);
        FahrerLink fl2 = new FahrerLink(f2, autos);

        System.out.println("a1-KFZ="+al1.getAuto().getKfzZeichen()+" hat folgende Fahrer:");
        System.out.println(al1.getDieFahrer()[0].getName());
        System.out.println(al1.getDieFahrer()[1].getName());

        System.out.println("a2-KFZ="+al2.getAuto().getKfzZeichen()+" hat folgende Fahrer:");
        System.out.println(al2.getDieFahrer()[0].getName());
        System.out.println(al2.getDieFahrer()[1].getName());

        System.out.println("a3-KFZ="+al2.getAuto().getKfzZeichen()+" hat folgende Fahrer:");
        System.out.println(al3.getDieFahrer()[0].getName());
        System.out.println(al3.getDieFahrer()[1].getName());

        System.out.println("fl1-Name="+fl1.getFahrer().getName()+"fährt folgende Autos:");
        System.out.println(fl1.getDieAutos()[0].getKfzZeichen());
        System.out.println(fl1.getDieAutos()[1].getKfzZeichen());
        System.out.println(fl1.getDieAutos()[2].getKfzZeichen());

        System.out.println("fl2-Name="+fl2.getFahrer().getName()+"fährt folgende Autos:");
        System.out.println(fl2.getDieAutos()[0].getKfzZeichen());
        System.out.println(fl2.getDieAutos()[1].getKfzZeichen());
        System.out.println(fl2.getDieAutos()[2].getKfzZeichen());
	}
}

class Auto{
	private String kfzZeichen;

	public Auto(String pKfzZeichen){
		kfzZeichen=pKfzZeichen;
	}

	public Auto(){
	}

	public void setKfzZeichen(String pKfzZeichen){
		kfzZeichen=pKfzZeichen;
	}

	public String getKfzZeichen(){
		return kfzZeichen;
	}


}

class Fahrer{
	private String name;

	public Fahrer(String pName){
		name = pName;
	}

	public void setName(String pName){
		name = pName;
	}

	public String getName(){
		return(name);
	}
}


class AutoLink{
	private Auto dasAuto;
	private Fahrer dieFahrer[];


	public AutoLink(Auto pAuto, Fahrer[] pDieFahrer){
        dasAuto = pAuto;
		dieFahrer = pDieFahrer;
	}

	public Auto getAuto(){
		return dasAuto;
	}

	public Fahrer[] getDieFahrer(){
		return dieFahrer;
	}

}

class FahrerLink{
	private Fahrer derFahrer;
	private Auto[] dieAutos;

	public FahrerLink(Fahrer pFahrer, Auto[] pDieAutos){
        derFahrer = pFahrer;
		dieAutos = pDieAutos;
	}

	public Fahrer getFahrer(){
		return(derFahrer);
	}

	public Auto[] getDieAutos(){
		return dieAutos;
	}
}
```


2) Version2
Bei  meiner 2. Version wird diese Rückverlinkung automatisch gemacht.
Das ganze wird aber sehr viel komplizierter.
Wie beurteilt ihr diese 2 Lösungen?


```
package assoziationbi_nzum_2;

public class MainAssoziationBI_NzuM_2 {
    public static void main(String[] args) {
        /* Zu realsisierende Verlinkungen:
        a1 --- f1
        a1 --- f2
        a2 --- f1
        a2 --- f2
        a3 --- f1
        a3 --- f2
        */
        Auto a1 = new Auto("A1");
        Auto a2 = new Auto("A2");
        Auto a3 = new Auto("A3");
        Fahrer f1 = new Fahrer("F1-Alice");
        Fahrer f2 = new Fahrer("F2-Berta");

        AutoLink al1 = new AutoLink(a1, f1, f2);
        AutoLink al2 = new AutoLink(a2, f1, f2);
        AutoLink al3 = new AutoLink(a3, f1, f2);

        al1.getFahrerLinks()[0].getAutoLinks()[1]=al2;
        al1.getFahrerLinks()[0].getAutoLinks()[2]=al3;
        al1.getFahrerLinks()[1].getAutoLinks()[1]=al2;
        al1.getFahrerLinks()[1].getAutoLinks()[2]=al3;

        al2.getFahrerLinks()[0].getAutoLinks()[1]=al1;
        al2.getFahrerLinks()[0].getAutoLinks()[2]=al3;
        al2.getFahrerLinks()[1].getAutoLinks()[1]=al1;
        al2.getFahrerLinks()[1].getAutoLinks()[2]=al3;

        al3.getFahrerLinks()[0].getAutoLinks()[1]=al1;
        al3.getFahrerLinks()[0].getAutoLinks()[2]=al2;
        al3.getFahrerLinks()[1].getAutoLinks()[1]=al1;
        al3.getFahrerLinks()[1].getAutoLinks()[2]=al2;

        System.out.println("al1="+al1.getAuto().getKFZZeichen());
        System.out.println("al1-Fahrer1-alle Wagen=");
        System.out.print(al1.getFahrerLinks()[0].getAutoLinks()[0].getAuto().getKFZZeichen());
        System.out.print(al1.getFahrerLinks()[0].getAutoLinks()[1].getAuto().getKFZZeichen());
        System.out.println(al1.getFahrerLinks()[0].getAutoLinks()[2].getAuto().getKFZZeichen());
        System.out.println("al1-Fahrer2-alle Wagen=");
        System.out.print(al1.getFahrerLinks()[1].getAutoLinks()[0].getAuto().getKFZZeichen());
        System.out.print(al1.getFahrerLinks()[1].getAutoLinks()[1].getAuto().getKFZZeichen());
        System.out.println(al1.getFahrerLinks()[1].getAutoLinks()[2].getAuto().getKFZZeichen());

        System.out.println("al2="+al2.getAuto().getKFZZeichen());
        System.out.println("al2-Fahrer1-alle Wagen=");
        System.out.print(al2.getFahrerLinks()[0].getAutoLinks()[0].getAuto().getKFZZeichen());
        System.out.print(al2.getFahrerLinks()[0].getAutoLinks()[1].getAuto().getKFZZeichen());
        System.out.println(al2.getFahrerLinks()[0].getAutoLinks()[2].getAuto().getKFZZeichen());
        System.out.println("al2-Fahrer2-alle Wagen=");
        System.out.print(al2.getFahrerLinks()[1].getAutoLinks()[0].getAuto().getKFZZeichen());
        System.out.print(al2.getFahrerLinks()[1].getAutoLinks()[1].getAuto().getKFZZeichen());
        System.out.println(al2.getFahrerLinks()[1].getAutoLinks()[2].getAuto().getKFZZeichen());

        System.out.println("al3="+al2.getAuto().getKFZZeichen());
        System.out.println("al3-Fahrer1-alle Wagen=");
        System.out.print(al3.getFahrerLinks()[0].getAutoLinks()[0].getAuto().getKFZZeichen());
        System.out.print(al3.getFahrerLinks()[0].getAutoLinks()[1].getAuto().getKFZZeichen());
        System.out.println(al3.getFahrerLinks()[0].getAutoLinks()[2].getAuto().getKFZZeichen());
        System.out.println("al3-Fahrer2-alle Wagen=");
        System.out.print(al3.getFahrerLinks()[1].getAutoLinks()[0].getAuto().getKFZZeichen());
        System.out.print(al3.getFahrerLinks()[1].getAutoLinks()[1].getAuto().getKFZZeichen());
        System.out.println(al3.getFahrerLinks()[1].getAutoLinks()[2].getAuto().getKFZZeichen());
    }
}


class Auto{
    private String kFZZeichen;

    public String getKFZZeichen() {
        return kFZZeichen;
    }

    public void setKFZZeichen(String kFZZeichen) {
        this.kFZZeichen = kFZZeichen;
    }

    public Auto(String kFZZeichen) {
        this.kFZZeichen = kFZZeichen;
    }
}


class Fahrer{
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Fahrer(String name) {
        this.name = name;
    }
}

class AutoLink {
    private Auto auto;
    private FahrerLink[] fahrerLinks;

    public AutoLink(Auto pAuto, Fahrer pFahrer1, Fahrer pFahrer2){
        auto = pAuto;
        fahrerLinks = new FahrerLink[2];
        fahrerLinks[0] = new FahrerLink(pFahrer1, this);
        fahrerLinks[1] = new FahrerLink(pFahrer2, this);
    }

    public FahrerLink[] getFahrerLinks(){
        return fahrerLinks;
    }

    public Auto getAuto(){
        return auto;
    }
}
```


3)
In meinen Programmen habe ich unterschieden zwischen einer "normalen" Klasse und einer Klasse die eine "normale" Klasse als Attribut enthält und einen Link auf eine andere "normale" Klasse enthält.
Ich habe z.B. diese Klassen mit Auto bzw. AutoLink bezeichnet.
Habt ihr bessere Ideen, wie man das bezeichnen soll?

mfg
Ernst


----------



## Final_Striker (13. Apr 2010)

Sag mooo... 
oben im Post steht doch wie man es macht.
Die Klasse Auto bekommt als Attribut eine Liste von Fahrern und die Klasse Fahrer eine Liste von Autos. Du brauchst weder die Klasse AutoLink noch die Klasse FahrerLink.


```
public class Auto{

   private List<Fahrer> fahrerListe = new ArrayList<Fahrer>();

   public void addFahrer(Fahrer fahrer)[
   
      fahrerListe.add(fahrer);
   }
}
```

und das gleiche umgekehrt für den Fahrer.


----------



## ernst (13. Apr 2010)

Final_Striker hat gesagt.:


> Sag mooo...
> oben im Post steht doch wie man es macht.
> Die Klasse Auto bekommt als Attribut eine Liste von Fahrern und die Klasse Fahrer eine Liste von Autos. Du brauchst weder die Klasse AutoLink noch die Klasse FahrerLink.
> 
> ...



1)
Das 1. Beispiel von mir:
class AutoLink{
    private Auto dasAuto;
    private Fahrer dieFahrer[];
 ...
}

ist doch das Gleiche, wie das von dir Vorgestellte, außer dass ich zusätzlich zu der Verlinkung 
private Fahrer dieFahrer[]
(ich hätte genauso eine ArrayList benutzen können)
die eigentlichen Eigenschaften, die ein Auto hat (Kfzkennzeichen, Hubraum, PS, usw.) in dem Attribut:
private Auto dasAuto;
speichere.

Oder siehst du das anders?

2)
Da ich die Bezeichnung Auto für die Klasse Auto verwende, brauche ich noch eine Bezeichnung für die Klasse, die noch zusätzlich zum Auto einen Link auf die Fahrerliste speichert.
Ich nenne diese Klasse AutoLink.
Oder was schlägst du vor?

Mit freundlichen Grüßen
Ernst


----------



## SlaterB (13. Apr 2010)

man kann für die Verknüpfung von Auto und Fahrer (ob einen oder mehrere) eine zusätzliche Klasse einrichten, 
z.B. wenn man die Ursprungsklasse nicht bearbeiten kann, sonst nämlich dort die Fahrer einfügen

der Name ist Ansichtssache, 
AutoLink ist etwas allgemein, was machst du wenn du später mal Auto <-> Reifen wieder in einer Klasse verlinken möchtest?
denkbar wäre AufoFahrer, einfach und gut


----------



## ernst (13. Apr 2010)

SlaterB hat gesagt.:


> man kann für die Verknüpfung von Auto und Fahrer (ob einen oder mehrere) eine zusätzliche Klasse einrichten,
> z.B. wenn man die Ursprungsklasse nicht bearbeiten kann, sonst nämlich dort die Fahrer einfügen


1) Ist meine Lösung (1. Beispiel von mir) akkzeptabel?

2) Kannst du mir das mit der zusätzlichen Klasse an einem Code-Beispiel demonstrieren?

3) In meinem 2. (komplizierteren) Beispiel habe ich die "Rückverlinkung" implementiert.
Was hältst du davon?
Ist das notwendig, oder verkompliziert das alles unnötig?



SlaterB hat gesagt.:


> der Name ist Ansichtssache,
> AutoLink ist etwas allgemein, was machst du wenn du später mal Auto <-> Reifen wieder in einer Klasse verlinken möchtest?
> denkbar wäre AufoFahrer, einfach und gut


Stimmt!
Was hältst du von AutoMitFahrern
bzw.
bei der anderen Klasse
FahrerMItAutos

mfg
Ernst


----------



## SlaterB (13. Apr 2010)

> Kannst du mir das mit der zusätzlichen Klasse an einem Code-Beispiel demonstrieren?

deine Klasse AutoLink IST doch so ein Beispiel,
sonst käme niemand auf die Idee, normal macht man es ohne, siehe Code von  Final_Striker, den du auch zitiert hast,
die Liste der Fahrer IN Auto

--------

> In meinem 2. (komplizierteren) Beispiel 

Seitensuche nach '2. beispiel' schlägt fehl


-------

> Was hältst du von AutoMitFahrern

an weiteren Namensdiskussionen beteilige ich mich nicht


----------



## ernst (13. Apr 2010)

SlaterB hat gesagt.:


> > Kannst du mir das mit der zusätzlichen Klasse an einem Code-Beispiel demonstrieren?
> 
> deine Klasse AutoLink IST doch so ein Beispiel,
> sonst käme niemand auf die Idee, normal macht man es ohne, siehe Code von  Final_Striker, den du auch zitiert hast,
> die Liste der Fahrer IN Auto


Ich verstehe leider den Sinn deines Satzes nicht:
Der Satz scheint abgebrochen zu sein. Irgendetwas fehlt grammatikalisch.



SlaterB hat gesagt.:


> > In meinem 2. (komplizierteren) Beispiel
> Seitensuche nach '2. beispiel' schlägt fehl


siehe:
public class MainAssoziationBI_NzuM_2 {


mfg
Ernst


----------



## SlaterB (13. Apr 2010)

> Ich verstehe leider den Sinn deines Satzes nicht:

es gibt Auto und Fahrer, die beiden Klassen sind unumstößlich,

entweder beläßt man es bei genau diesen beiden Klassen und baut die Verbindung in diese Klassen rein, siehe Code von Final-Striker
ODER
man erfindet eine dritte zusätzliche Klasse wie du es mit AutoLink gemacht hast

-------

> MainAssoziationBI_NzuM_2

puh, die Anfänge hatte ich bisher nicht gelesen und sieht auch etwas aufwendig aus,
kannst du nochmal skizzieren, was deine Frage dazu ist und was da die beiden Beispiele unterscheidet?

etwas schwierig scheint mir die Sache auch dadurch, dass in Beispiel 2 in AutoLink FahrerLink benutzt wird,
diese Klasse in Beispiel 2 aber gar nicht enthalten ist, sondern nur in Beispiel 1, mit nicht passenden Konstruktor

> oder verkompliziert das alles unnötig?

aber hallo, ich denke ja


----------



## ernst (13. Apr 2010)

SlaterB hat gesagt.:


> > Ich verstehe leider den Sinn deines Satzes nicht:
> 
> es gibt Auto und Fahrer, die beiden Klassen sind unumstößlich,
> 
> ...


1) Der Unterschied von Final-Striker zu meinem 1. Beispiel ist doch, dass er außer dem Link auf die Fahrerliste kein weiteres Attribut in die Klasse Auto aufgenommen hat.
Aber eine ausführlichere Version müsste noch ein paar weitere Attribute von Auto enthalten, wie z.B:
private double kfzNummer;
private int ps;
private int hubraum;
usw.
Ich habe diese Attribute (außer der Verlinkung) in eine eigene Klasse Auto gepackt und in eine andere Klasse AutoMitFahrern
würde ich dann packen:
private Auto auto;
private Fahrer[] fahrerListe;

Warum findest du diesen Vorschlag von mir nicht gut?



SlaterB hat gesagt.:


> > MainAssoziationBI_NzuM_2
> 
> puh, die Anfänge hatte ich bisher nicht gelesen und sieht auch etwas aufwendig aus,
> kannst du nochmal skizzieren, was deine Frage dazu ist und was da die beiden Beispiele unterscheidet?
> ...


Du hast Recht (Entschuldigung): Mein Programm war nicht vollständig, obwohl ich meinte alles reinkopiert zu haben.
In der Version unten dürfte alles enthalten sein.
In dieser neuen Version befindet sich (ich nennen es so) die "Rückverlinkung".
Beispiel:
a1 --- f1
a1 --- f2
a2 --- f1
a2 --- f2
a3 --- f1
a3 --- f2

Wenn ich eine Assoziation, wie z.B:
a1 --> {f1, f2}
realisiert habe, muß in der Liste, die f1 zugewiesen wird, logischerweise a1 enthalten sein ("Rückverlinkung", wegen bidirektional).
Bei meiner 1. Version wird die Rückverlinkung nicht innerhalb des Konstruktors gemacht, aber in der Version unten wird die Rückverlinkung innerhalb des Konstruktors gemacht.


mfg
Ernst


```
package assoziationbi_nzum_2;

public class MainAssoziationBI_NzuM_2 {
    public static void main(String[] args) {
        /* Zu realsisierende Verlinkungen:
        a1 --- f1
        a1 --- f2
        a2 --- f1
        a2 --- f2
        a3 --- f1
        a3 --- f2
        */
        Auto a1 = new Auto("A1");
        Auto a2 = new Auto("A2");
        Auto a3 = new Auto("A3");
        Fahrer f1 = new Fahrer("F1-Alice");
        Fahrer f2 = new Fahrer("F2-Berta");

        AutoLink al1 = new AutoLink(a1, f1, f2);
        AutoLink al2 = new AutoLink(a2, f1, f2);
        AutoLink al3 = new AutoLink(a3, f1, f2);

        al1.getFahrerLinks()[0].getAutoLinks()[1]=al2;
        al1.getFahrerLinks()[0].getAutoLinks()[2]=al3;
        al1.getFahrerLinks()[1].getAutoLinks()[1]=al2;
        al1.getFahrerLinks()[1].getAutoLinks()[2]=al3;

        al2.getFahrerLinks()[0].getAutoLinks()[1]=al1;
        al2.getFahrerLinks()[0].getAutoLinks()[2]=al3;
        al2.getFahrerLinks()[1].getAutoLinks()[1]=al1;
        al2.getFahrerLinks()[1].getAutoLinks()[2]=al3;

        al3.getFahrerLinks()[0].getAutoLinks()[1]=al1;
        al3.getFahrerLinks()[0].getAutoLinks()[2]=al2;
        al3.getFahrerLinks()[1].getAutoLinks()[1]=al1;
        al3.getFahrerLinks()[1].getAutoLinks()[2]=al2;

        System.out.println("al1="+al1.getAuto().getKFZZeichen());
        System.out.println("al1-Fahrer1-alle Wagen=");
        System.out.print(al1.getFahrerLinks()[0].getAutoLinks()[0].getAuto().getKFZZeichen());
        System.out.print(al1.getFahrerLinks()[0].getAutoLinks()[1].getAuto().getKFZZeichen());
        System.out.println(al1.getFahrerLinks()[0].getAutoLinks()[2].getAuto().getKFZZeichen());
        System.out.println("al1-Fahrer2-alle Wagen=");
        System.out.print(al1.getFahrerLinks()[1].getAutoLinks()[0].getAuto().getKFZZeichen());
        System.out.print(al1.getFahrerLinks()[1].getAutoLinks()[1].getAuto().getKFZZeichen());
        System.out.println(al1.getFahrerLinks()[1].getAutoLinks()[2].getAuto().getKFZZeichen());

        System.out.println("al2="+al2.getAuto().getKFZZeichen());
        System.out.println("al2-Fahrer1-alle Wagen=");
        System.out.print(al2.getFahrerLinks()[0].getAutoLinks()[0].getAuto().getKFZZeichen());
        System.out.print(al2.getFahrerLinks()[0].getAutoLinks()[1].getAuto().getKFZZeichen());
        System.out.println(al2.getFahrerLinks()[0].getAutoLinks()[2].getAuto().getKFZZeichen());
        System.out.println("al2-Fahrer2-alle Wagen=");
        System.out.print(al2.getFahrerLinks()[1].getAutoLinks()[0].getAuto().getKFZZeichen());
        System.out.print(al2.getFahrerLinks()[1].getAutoLinks()[1].getAuto().getKFZZeichen());
        System.out.println(al2.getFahrerLinks()[1].getAutoLinks()[2].getAuto().getKFZZeichen());

        System.out.println("al3="+al2.getAuto().getKFZZeichen());
        System.out.println("al3-Fahrer1-alle Wagen=");
        System.out.print(al3.getFahrerLinks()[0].getAutoLinks()[0].getAuto().getKFZZeichen());
        System.out.print(al3.getFahrerLinks()[0].getAutoLinks()[1].getAuto().getKFZZeichen());
        System.out.println(al3.getFahrerLinks()[0].getAutoLinks()[2].getAuto().getKFZZeichen());
        System.out.println("al3-Fahrer2-alle Wagen=");
        System.out.print(al3.getFahrerLinks()[1].getAutoLinks()[0].getAuto().getKFZZeichen());
        System.out.print(al3.getFahrerLinks()[1].getAutoLinks()[1].getAuto().getKFZZeichen());
        System.out.println(al3.getFahrerLinks()[1].getAutoLinks()[2].getAuto().getKFZZeichen());
    }
}


class Auto{
    private String kFZZeichen;

    public String getKFZZeichen() {
        return kFZZeichen;
    }

    public void setKFZZeichen(String kFZZeichen) {
        this.kFZZeichen = kFZZeichen;
    }

    public Auto(String kFZZeichen) {
        this.kFZZeichen = kFZZeichen;
    }
}


class Fahrer{
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Fahrer(String name) {
        this.name = name;
    }
}

class AutoLink {
    private Auto auto;
    private FahrerLink[] fahrerLinks;

    public AutoLink(Auto pAuto, Fahrer pFahrer1, Fahrer pFahrer2){
        auto = pAuto;
        fahrerLinks = new FahrerLink[2];
        fahrerLinks[0] = new FahrerLink(pFahrer1, this);
        fahrerLinks[1] = new FahrerLink(pFahrer2, this);
    }

    public FahrerLink[] getFahrerLinks(){
        return fahrerLinks;
    }

    public Auto getAuto(){
        return auto;
    }


}

class FahrerLink {
    private Fahrer fahrer;
    private AutoLink[] autoLinks;

    public FahrerLink(Fahrer pFahrer, AutoLink al){
        fahrer = pFahrer;
        autoLinks = new AutoLink[3];
        autoLinks[0] = al;
    }

    public AutoLink[] getAutoLinks(){
        return autoLinks;
    }

    public Fahrer getFahrer(){
        return fahrer;
    }
}
```


----------



## SlaterB (13. Apr 2010)

> Der Unterschied von Final-Striker zu meinem 1. Beispiel ist doch, dass er außer dem Link auf die Fahrerliste kein weiteres Attribut in die Klasse Auto aufgenommen hat.

also das war gewiss nur ein Mini-Beispiel im Forum, die anderen Attribute gehören selbstverständig auch in Auto,
je nachdem was man so hat

---------

> Warum findest du diesen Vorschlag von mir nicht gut?

jede zusätzliche Klasse ist schlecht, doppelte Arbeit,
was soll man dazu sagen? das zeigt erst die Erfahrung im Umgang mit den Klassen, besonder wenn zig Attribute gleichzeitig zu verlinken sind,
komplizierter Aufbau komplizierte Änderung, komplizierterer Zugriff, sieht man ja an deinem Programm


---------

dein Code ist nach wie vor sehr kompliziert und unnötig,
Zeile 23 bis 36 will doch niemand hintippen, wenn stattdessen auch 
a1.addFahrer(f1);
a1.addFahrer(f2);

a2.addFahrer(f1);
a2.addFahrer(f2);

a3.addFahrer(f1);
a3.addFahrer(f2);

oder ähnliches geht


----------



## ernst (13. Apr 2010)

SlaterB hat gesagt.:


> > Der Unterschied von Final-Striker zu meinem 1. Beispiel ist doch, dass er außer dem Link auf die Fahrerliste kein weiteres Attribut in die Klasse Auto aufgenommen hat.
> 
> also das war gewiss nur ein Mini-Beispiel im Forum, die anderen Attribute gehören selbstverständig auch in Auto,
> je nachdem was man so hat
> ...



Angenommen, jemand hat schon irgendwelche "Grundklassen" geschrieben, wie z.B. Auto, in der als Attribute so grundlegende Sachen vorkommen wie 
kfzZeichen
pS
Hubraum
anzahlTueren,
usw.
Allerdings fehlen noch Verlinkungen.
(Bem: Die StandardJava-Klassen (wie z.B. der GUI) sind ja auch schon da.)
Nun müssen die "Grundklassen" noch verlinkt werden.
Dazu geht man dann so vor wie ich beschrieben habe.
Ist das keine gute Idee?

mfg
Ernst


----------



## SlaterB (13. Apr 2010)

wenn man die Ursprungsklassen nicht ändern kann oder will, dann kann man weitere Klassen einführen, richtig,
habe ich ja auch schon mehr oder weniger für denkbar erklärt (gut oder schlecht ist da relativ)

in dem Fall kann man noch über den Aufwand nachdenken,
wenn du beide Sichten von Fahrer und Auto aus haben willst, dann sind auch gleich zwei Klasse AutoLink, FahrerLink denkbar, ja

die Umsetzung ist meiner Ansicht nach zur Hälfte unschön, 
du hast darauf geachtet, dass es pro Auto nur genau einen AutoLink gibt,
die FahrerLinks sind dagegen mehrfach pro Fahrer vorhanden, deshalb von Zeile 23-36 so viel zu tun,
wobei im anderen Fall auch einige Zeilen dazukämen

aber wenn erstmal viele Fahrer und viele Autos dazukommen, nicht immer genau mit den Zahlen 2 und 3,
dann wird das auf diese Weise nicht mehr zu handeln sein, dann doch besser einzelne FahrerLinks, 
und mehr Hilfsmethoden,

statt
al1.getFahrerLinks()[0].getAutoLinks()[1] = al2;
al1.getFahrerLinks()[0].getAutoLinks()[2] = al3;
z.B.
fl1.addAutoLinks(al2, al3);

-----

die Ausgabe geht natürlich überhaupt nicht, statt

        System.out.println("al1-Fahrer1-alle Wagen=");
        System.out.print(al1.getFahrerLinks()[0].getAutoLinks()[0].getAuto().getKFZZeichen());
        System.out.print(al1.getFahrerLinks()[0].getAutoLinks()[1].getAuto().getKFZZeichen());
        System.out.println(al1.getFahrerLinks()[0].getAutoLinks()[2].getAuto().getKFZZeichen());

muss da stehen

        System.out.println("al1-Fahrer1-alle Wagen=");
        System.out.print(al1.getFahrerLinks(0).getAlleWagen());

von außen kann man ja gar nicht wissen, wieviele AutoLinks vorhanden sind


-----

von solchen Details abgesehen ist das aber mit diesen Klassen durchaus realisierbar, ja,

gut fände ich persönlich etwas weniger Links und mehr Maps,
lieber viel Arbeit in Basisklassen stecken, als Detailklassen zu programmieren,
aber das ist jetzt ein kompliziertes Beispiel, musst du nicht so machen



```
public class Test
{
    public static void main(String[] args)
        throws Exception
    {
        MainAssoziationBI_NzuM_2.main(null);
    }
}

class MainAssoziationBI_NzuM_2
{
    public static void main(String[] args)
    {

        Auto a1 = new Auto("A1");
        Auto a2 = new Auto("A2");
        Auto a3 = new Auto("A3");
        Fahrer f1 = new Fahrer("F1-Alice");
        Fahrer f2 = new Fahrer("F2-Berta");
        Fahrer f3 = new Fahrer("Joe");

        AutoFahrerLinker afl = new AutoFahrerLinker();
        afl.add(a1, f1);
        afl.add(a2, f1);
        afl.add(a3, f2);
        afl.add(a1, f2);
        afl.add(a2, f3);
        afl.add(a3, f3);


        System.out.println("a1=" + a1);
        List<Fahrer> fahrerFuerA1 = afl.getFahrer(a1);
        for (int i = 0; i < fahrerFuerA1.size(); i++)
        {
            Fahrer f = fahrerFuerA1.get(i);
            System.out.print("a1-Fahrer" + (i + 1) + "-alle Wagen=");
            System.out.println(afl.getAutos(f));
        }
    }
}


class Auto
{
    private String kFZZeichen;

    public String getKFZZeichen()
    {
        return kFZZeichen;
    }

    public void setKFZZeichen(String kFZZeichen)
    {
        this.kFZZeichen = kFZZeichen;
    }

    public Auto(String kFZZeichen)
    {
        this.kFZZeichen = kFZZeichen;
    }

    public String toString()
    {
        return this.kFZZeichen;
    }
}


class Fahrer
{
    private String name;

    public String getName()
    {
        return name;
    }

    public void setName(String name)
    {
        this.name = name;
    }

    public Fahrer(String name)
    {
        this.name = name;
    }

    public String toString()
    {
        return this.name;
    }
}


class AutoFahrerLinker
{
    private AnyMap<Auto, Fahrer> afMap = new AnyMap<Auto, Fahrer>();
    private AnyMap<Fahrer, Auto> faMap = new AnyMap<Fahrer, Auto>();

    public void add(Auto a, Fahrer f)
    {
        afMap.add(a, f);
        faMap.add(f, a);
    }

    public List<Auto> getAutos(Fahrer f)
    {
        return faMap.get(f);
    }

    public List<Fahrer> getFahrer(Auto a)
    {
        return afMap.get(a);
    }
}


class AnyMap<T, U>
{
    private Map<T, List<U>> map = new HashMap<T, List<U>>();

    public void add(T t, U u)
    {
        List<U> list = map.get(t);
        if (list == null)
        {
            list = new ArrayList<U>();
            map.put(t, list);
        }
        list.add(u);
    }

    public List<U> get(T t)
    {
        return map.get(t);
    }

}
```
je nach Geschmack ist das sogar komplizierter, etwa durch neue Zwischenvariablen wie
> List<Fahrer> fahrerFuerA1 = ..


----------



## Wortraum (13. Apr 2010)

ernst hat gesagt.:


> Nun müssen die "Grundklassen" noch verlinkt werden.
> Dazu geht man dann so vor wie ich beschrieben habe.
> Ist das keine gute Idee?


Es ist jedenfalls unlesbar und unverständlich. Du solltest lesbare und sinnvolle Namen verwenden; von einer Nummerierung mit Buchstaben und Ziffern, noch dazu mit 1 und l, ist dringend abzuraten. Es sollten auch nicht plötzlich irgendwo im Quelltext Indizes auftauchen, von denen kein Mensch weiß, was sie bedeuten. Und schließlich solltest Du Listen oder ähnliche Datenstrukturen den einfachen Feldern vorziehen.

Du möchtest übrigens Beziehungen zwischen Objekten, nicht zwischen Klassen abbilden. Eine Möglichkeit wäre zum Beispiel die Vererbung, falls man an Auto oder Fahrer nichts ändern kann. Eine eigene Klasse, die nur die Beziehungen enthält, also Deine Idee, ist natürlich auch gut. Man kann auch einfach Listen und Abbildungen verwenden:

```
private Map<Auto, List<Fahrer>> autosFahrer = new HashMap<Auto, List<Fahrer>>();
private Map<Fahrer, List<Auto>> fahrerAutos = new HashMap<fahrer, List<Autos>>();
```

Wie man sieht, hat man aber immer zwei Datenstrukturen, die man bei einer Änderung aktualisieren muß. Das ist umständlich zu programmieren, so daß man am Ende vermutlich doch wieder bei einer eigenen Klasse landet, so wie SlaterB es in seinem Beispiel hat (AutoFahrerLink).

Außerdem sieht man, daß man eine Abbildung von Auto auf eine Liste mit Fahrern hat (Map <Auto, List<Fahrer>>); und von Fahrern auf eine Liste mit Autos. Damit man nicht ständig mit Listen herumhantiert, nur weil man einen Fahrer oder ein Auto hinzufügen möchte, ist sogar noch eine weitere Klasse sinnvoll. Bei SlaterB heißt sie AnyMap. Das vereinfacht das ganze auf AnyMap<Auto, Fahrer>.

Doch noch etwas zu einem Deiner Konstruktoren:

```
public AutoLink(Auto pAuto, Fahrer pFahrer1, Fahrer pFahrer2){
        auto = pAuto;
        fahrerLinks = new FahrerLink[2];
        fahrerLinks[0] = new FahrerLink(pFahrer1, this);
        fahrerLinks[1] = new FahrerLink(pFahrer2, this);
}
```
Das ist zu starr. Was machst Du, wenn es drei Fahrer für ein Auto gibt? Vergleiche das mit SlaterBs Beispiel, in dem man einen weiteren Fahrer mit add(Fahrer) hinzufügen kann.

Auch Deinen Konstruktor kann man flexibler machen:

```
private Auto auto;
private List<Fahrer> fahrer;
 
public AutoLink(Auto pAuto, List<Fahrer> pFahrer){
    auto = pAuto;
    fahrer = pFahrer;
}
```

Oder, wenn Du bei Feldern bleiben möchtest, mit einer beliebigen Anzahl an Parametern:

```
private Auto auto;
private FahrerLink[] fahrerLinks;
 
public AutoLink(Auto pAuto, Fahrer... pFahrer){
    auto = pAuto;
    fahrerLinks = pFahrer;
}
```
Bei Dir kann man später allerdings keine Fahrer mehr hinzufügen, sondern muß das immer bei der Objekterzeugung machen. Das ließe sich später recht problemlos erweitern, aber es ist jedenfalls etwas, dessen man sich bewußt sein sollte.

Ich vermute, Du mußt Dir überhaupt erst anschauen, wie das mit Listen und den Typargumenten (<Typ>) funktioniert. Schau es Dir am besten mal an und probier ein bißchen herum. Diese Hürde zu nehmen ist wichtig, da man später viel mit Listen (und ähnlichen Datenstrukturen) macht.


----------



## ernst (14. Apr 2010)

@ SlaterB und @Wortraum

Erst mal Danke für eure Tipps.
Ich will mal zuerst mit reinen Arrays arbeiten, dann später mit dynamischen Arrays (Listen).
Ich kenne dynamische Arrays, von Maps habe ich dagegen keine Ahnung.
Dies werde ich mir später noch anschauen.
Könnt ihr mir ganz kurz (in ein paar Worten) beschreiben, um was es bei Maps geht
(habe mal gehört, daß Maps mit Schlüsseln zusammenhängen).

1) Ich habe mir nochmals grundlegende Gedanken gemacht.
Mathematisch geht es darum, eine Relation zu realisieren, d.h. eine  Teilmenge von A x B
Bei einer bidirektionalen Assoziation muß man dann noch die entsprechende (induzierte) Teilmenge von B x A 
betrachten (Rückverlinkung). Wie das mathematisch heißt, weiß ich nicht.
Beispiel1 (siehe Programm ganz unten):

```
a1  a2  a3   ZSum
f1    1   1   1    3
f2    1   1   1    3
SSum  2   2   2
```
Eine 1 in der Matrix bedeutet, dass zwischen diesen beiden Elementen eine Relation besteht.
Eine 0 würde bedeuten, dass keine Relation besteht:
ZSum bedeutet Zeilensumme
SSum bedeutet Spaltensumme

Beispiel2: (Unterschied zu Beispiel1 ist nur, dass zwischen a1 und f1 keine Relation besteht

```
a1  a2  a3   ZSum
f1    0   1   1    2
f2    1   1   1    3
SSum  1   2   2
```

Mein Programm unten soll folgendes machen:
Von einer _beliebigen_ Matrix (Im Beispiel1 von einer 2 x 3 Matrix) , die eine Relation beschreibt, soll das Programm automatisch die Assoziationen erstellen.
Von der Matrix (besteht aus 0 en und 1 en) ist die Zeilenanzahl und Spaltenanzahl gegeben.
Das Programm berechnet zuerst die Zeilensummen und Spaltensummen, um nachher die Länge der jeweiligen Listen zu berechnen.
Zum Schluß wird zu Testzwecken nochmals die Assoziationen auf dem Bildschirm ausgegeben.

Bei dieser Version wird die Rückverlinkung _nicht_ innerhalb des Konstruktors gemacht, sondern die Objekte 
AutoMitFahrern af[] = new AutoMitFahrern[anzSpalten-1];
FahrerMitAutos fa[] = new FahrerMitAutos[anzZeilen-1];
werden explizit in main erstellt

Was haltet ihr von dieser Lösung?


```
package assoziationbi_nzum_3;

public class MainAssoziationBI_NzuM_3 {

    public static void main(String[] args) {
        final int anzSpalten = 4;
        final int anzZeilen = 3;
        int i,j,index;
        /* Zu realsisierende Verlinkungen:
        a1 --- f1
        a1 --- f2
        a2 --- f1
        a2 --- f2
        a3 --- f1
        a3 --- f2

        als Matrix:
           a1  a2  a3  Sum
        f1  1   1   1  2
        f2  1   1   1  2
       sum  2   2
        */

        // Autos und Fahrer erzeugen
        Auto[] autos = new Auto[anzSpalten-1];
        Fahrer[] fahrer = new Fahrer[anzZeilen-1];
        for(j=0;j<anzSpalten-1;j++){
            autos[j] = new Auto("A"+Integer.toString(j));
        }

        for(i=0;i<anzZeilen-1;i++){
            fahrer[i] = new Fahrer("F"+Integer.toString(i));
        }

        // Autos mit Fahrern bzw
        // Fahrer mit Autos erzeugen
        AutoMitFahrern af[] = new AutoMitFahrern[anzSpalten-1];
        FahrerMitAutos fa[] = new FahrerMitAutos[anzZeilen-1];

        // Relationen durch Matrix festlegen
        int[][] matrix = new int[anzZeilen][anzSpalten];

        // initialisieren
        for(i=0;i<anzZeilen;i++)
            for(j=0;j<anzSpalten;j++)
                matrix[i][j]=0;

        for(i=0;i<anzZeilen-1;i++)
            for(j=0;j<anzSpalten-1;j++)
                matrix[i][j]=1;


        //matrix[0][0]=0;

        // Zeilensummen und Spaltensummen bestimmen
        for(i=0;i<anzZeilen-1;i++){
            for(j=0;j<anzSpalten-1;j++){
                matrix[i][anzSpalten-1]=matrix[i][anzSpalten-1]+matrix[i][j];
                matrix[anzZeilen-1][j]=matrix[anzZeilen-1][j]+matrix[i][j];
            }
        }

        // Links festlegen
        for(i=0;i<anzZeilen-1;i++){
            fa[i]=new FahrerMitAutos(fahrer[i], matrix[i][anzSpalten-1]);
        }

        for(j=0;j<anzSpalten-1;j++){
            af[j]=new AutoMitFahrern(autos[j], matrix[anzZeilen-1][j]);
        }

        // Autos --> Fahrer zuordnen
        index=0;
        for(i=0;i<anzZeilen-1;i++){
            for(j=0;j<anzSpalten-1;j++){
                if(matrix[i][j]==1){
                    fa[i].setAutoToFahrer(index, autos[j]);
                    index++;
                }
            }
            index=0;
        }

        // Fahrer --> Autos zuordnen
        index=0;
        for(j=0;j<anzSpalten-1;j++){
            for(i=0;i<anzZeilen-1;i++){
                if(matrix[i][j]==1){
                    af[j].setFahrerToAuto(index, fahrer[i]);
                    index++;
                }
            }
            index=0;
        }

        // Zum Nachprüfen:
        for(i=0;i<anzZeilen-1;i++){
            fa[i].print();
        }
        for(i=0;i<anzSpalten-1;i++){
            af[i].print();
        }


    }
}

class Auto{
	private String kfzZeichen;

	public Auto(String pKfzZeichen){
		kfzZeichen=pKfzZeichen;
	}

	public Auto(){
	}

	public void setKfzZeichen(String pKfzZeichen){
		kfzZeichen=pKfzZeichen;
	}

	public String getKfzZeichen(){
		return kfzZeichen;
	}


}

class Fahrer{
	private String name;

	public Fahrer(String pName){
		name = pName;
	}

	public void setName(String pName){
		name = pName;
	}

	public String getName(){
		return(name);
	}
}

class AutoMitFahrern{
	private Auto dasAuto;
	private Fahrer dieFahrer[];

	public AutoMitFahrern(Auto pAuto, int anzahl){
        dasAuto = pAuto;
        dieFahrer = new Fahrer[anzahl];
    }

	public AutoMitFahrern(Auto pAuto, Fahrer[] pDieFahrer){
            dasAuto = pAuto;
            dieFahrer = pDieFahrer;
	}

	public void setFahrerToAuto(int index, Fahrer pFahrer){
            dieFahrer[index] = pFahrer;
        }


	public Auto getAuto(){
		return dasAuto;
	}

	public Fahrer[] getDieFahrer(){
		return dieFahrer;
	}

    public void print(){
        System.out.print("Auto-KFZ="+dasAuto.getKfzZeichen());
        System.out.print("  Dazugehörige Fahrerliste: ");
        for(int i=0;i<dieFahrer.length;i++){
            System.out.print(dieFahrer[i].getName()+" ");
        }
        System.out.println("");
    }

}

class FahrerMitAutos{
	private Fahrer derFahrer;
	private Auto[] dieAutos;

	public FahrerMitAutos(Fahrer pFahrer, int anzahl){
        derFahrer = pFahrer;
        dieAutos = new Auto[anzahl];
    }

	public FahrerMitAutos(Fahrer pFahrer, Auto[] pDieAutos){
        derFahrer = pFahrer;
		dieAutos = pDieAutos;
	}

	public void setAutoToFahrer(int index, Auto pAuto){
            dieAutos[index] = pAuto;
        }

    public Fahrer getFahrer(){
		return(derFahrer);
	}

	public Auto[] getDieAutos(){
		return dieAutos;
	}

    public void print(){
        System.out.print("Fahrer-Name="+derFahrer.getName());
        System.out.print("  Dazugehörige Autoliste: ");
        for(int i=0;i<dieAutos.length;i++){
            System.out.print(dieAutos[i].getKfzZeichen()+" ");
        }
        System.out.println("");
    }

}
```









2)
In einer neuen Version will ich die Rückverlinkungen innerhalb des Konstruktors machen.
In main wird also nur 
AutoMitFahrern af[] = new AutoMitFahrern[anzSpalten-1];
angelegt.
FahrerMitAutos fa[] 
wird also im Konstruktor erzeugt.
Ob das geht weiß ich nicht.
Ich bin noch am Probieren.

mfg
Ernst


----------

