Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
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?
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.
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?
Es gibt in dem Sinne kein Schema. Eine Assoziation ist ja nichts anderes als eine Variable mit einer Referenz auf ein anderes Objekt.
Code:
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.
Code:
public void setAutos(List<Auto> autos) {
vieleAssoziationen = autos;
for (Auto a : autos) {
a.setAutohaus(this);
}
}
Oder beispielsweise „außerhalb“ des Autohauses:
Code:
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.
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);
Java:
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?
Java:
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?
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.
Java:
public class Auto{
private List<Fahrer> fahrerListe = new ArrayList<Fahrer>();
public void addFahrer(Fahrer fahrer)[
fahrerListe.add(fahrer);
}
}
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.
Java:
public class Auto{
private List<Fahrer> fahrerListe = new ArrayList<Fahrer>();
public void addFahrer(Fahrer fahrer)[
fahrerListe.add(fahrer);
}
}
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?
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
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?
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
> 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
> 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:
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
> 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
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?
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
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
Java:
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;
}
}
> 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);
> 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
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?
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);
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
Java:
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 = ..
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:
Code:
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:
Code:
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:
Code:
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:
Code:
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.
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):
Java:
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
Java:
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?
Java:
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.