Kompositum mit vorgegebener hierarchischer Struktur

Mappenz

Bekanntes Mitglied
Dies ist die Aufgabe, die gestern schon diskutiert wurde. http://www.java-forum.org/java-basics-anfaenger-themen/119919-singleton-parametern-konstruktor.html

Ich habe mittlerweile auch erkannt, dass das Kompositum Muster gut anwendbar ist. Allerdings hänge ich an einem Detail.

Der Code sieht bis jetzt so aus.

Java:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

abstract public class Geschaeftsfuehrer extends Person{ //Kompositum
	protected List<Person> komp = new ArrayList<Person>();
	
    public Geschaeftsfuehrer(String vname, String nname) {
        super(vname, nname);
    }
    
    public boolean fuegeHinzu(Person komp) {
    	this.komp.add(komp);
		return true;
	}
    
    public boolean entferne(Person komp) {
    	try {
    		this.komp.remove(this.komp.indexOf(komp));
    		
    	} catch(IndexOutOfBoundsException e) {
    		//could only be -1, lets ignore this case
    	}
		return true;
	}
    public Iterator<Person> erzeugeIterator(){
    	return komp.iterator();
    }

}

Java:
import java.util.Iterator;
import java.util.NoSuchElementException;

abstract public class Person { //Komponente
    // bei uns verdienen erst einmal alle gleich viel ...
    int gehalt = 42;
    String vorname = null;
    String nachname = null;
    
    public Person(String vname, String nname) {
        vorname = vname;
        nachname = nname;
    }
    
    public String gibName() {
        return vorname + " " + nachname;
    }
    
    public boolean fuegeHinzu(Person komp) {
		return false;
	}
    
    public boolean entferne(Person komp) {
		return false;
	}
    
    //return a null iterator
    public Iterator<Person> erzeugeIterator() {
    	return new Iterator<Person>() {

			@Override
			public boolean hasNext() {
				return false;
			}

			@Override
			public Person next() {
				throw new NoSuchElementException();
			}

			@Override
			public void remove() {
				throw new UnsupportedOperationException();				
			}
		};
    }
    
}

Java:
public class Mitarbeiter extends Person{//Blatt
    public Mitarbeiter(String vname, String nname) {
        super(vname, nname);
    }

}

Java:
public class Teamleiter extends Abteilungsleiter {    
    public Teamleiter(String vname, String nname) {
        super(vname, nname);
    }
}

Java:
public class Abteilungsleiter extends Geschaeftsfuehrer {
    public Abteilungsleiter(String vname, String nname) {
        super(vname, nname);
    }
    
}

Wobei die Teamleiter und Abteilungsleiter noch nutzlos sind. Diese Klassen existieren damit ich hier hänge ich) den Objekten eine Hierarchie aufzwingen kann. Und zwar soll der Geschaeftsfuehrer ausschließlich Abteilungsleiter verwalten, der Abteilungsleiter ausschließlich Teamleiter, der Teamleiter ausschließlich Mitarbeiter. Wärend das nicht realitätsnah ist habe ich dieses Verhalten im Orginalcode ausgemacht und glaube das beizubehalten ist Teil der Übung. Mein Code erlaubt auch noch beliebig tiefe abstiege in der Hierarchie, bei Tiefe 3 sollte aber Schluss sein.

Nun kann ich natürlich nicht in den Abteilungsleiter schreiben:
Java:
@Override
public boolean fuegeHinzu(Teamleiter tl) {
	komp.add(tl);
	return true;
}
Da alle Klassen von einander Erben macht es auch keinen Sinn, in Person
Java:
 public boolean fuegeHinzu(Teamleiter komp) {
		return false;
	}
zu schreiben.

Ist es eine Gute Idee die Vererbungshierarchie Umzukehren, So, dass der Geschaeftsfuehrer ganz unten steht. Dann sollten die beiden Ansätze funktionieren. Es erscheint mir konterintuitiv.
 

Mappenz

Bekanntes Mitglied
Ich habe nun die Vererbungshierarchie umgekehrt. sie sieht nun so aus.
Code:
 Person <-- Mitarbeiter <-- Teamleiter <-- Abteilungsleiter <-- Geschaeftsfuehrer
Mitarbeiter bleibt das einzige Blatt.
Es habe sich Teamleiter und Geschaeftsfuehrer geändert
Java:
abstract public class Geschaeftsfuehrer extends Abteilungsleiter{
	
    public Geschaeftsfuehrer(String vname, String nname) {
        super(vname, nname);
    }
    @Override
    public boolean fuegeHinzu(Abteilungsleiter komp) {
    	this.komp.add(komp);
		return true;
	}

}

Java:
public class Teamleiter extends Mitarbeiter {    
    public Teamleiter(String vname, String nname) {
        super(vname, nname);
    }
    protected List<Person> komp = new ArrayList<Person>();
    @Override
    public boolean fuegeHinzu(Mitarbeiter komp) {
    	this.komp.add(komp);
		return true;
	}
    
    public boolean entferne(Person komp) {
    	try {
    		this.komp.remove(this.komp.indexOf(komp));
    		
    	} catch(IndexOutOfBoundsException e) {
    		//could only be -1, lets ignore this case
    	}
		return true;
	}
    public Iterator<Person> erzeugeIterator(){
    	return komp.iterator();
    }
}


Ich hatte gehofft mir nun die Kovarianz zu Nutze machen zu können. Aber das schlägt Fehl, ich habe schon getestet ob mich mein Verständnis der Kovarianz trügt indem ich
Java:
    public boolean fuegeHinzu(Teamleiter komp) {
		return false;
	}
in Person stehen hatte und dann in Teamleiter versucht habe diese Funktion so zu überschreiben:

Java:
    @Override
    public boolean fuegeHinzu(Mitarbeiter komp) {
    	this.komp.add(komp);
		return true;
	}
und
Java:
    @Override
    public boolean fuegeHinzu(Abteilungsleiter komp) {
    	this.komp.add(komp);
		return true;
	}
zu meiner Überraschung waren beide nicht möglich. Ich hätte erwartet, dass die erste Version in Ordnung ist. Dass beide nicht gehen kann ich überhaupt nicht erklären.
 
Zuletzt bearbeitet:

schalentier

Gesperrter Benutzer
Du hast mehrere Moeglichkeiten, ich kenn ja die genaue Aufgabenstellung nicht.

1. Du formulierst das Komposite Muster in allen drei Klassen aus:
Java:
public abstract class Person {
   // ... gehalt, name, etc
} 
public class Geschaeftsfuehrer extends Person {
   private List<Abteilungsleiter> abteilungsleiters = new ArrayList<...>();
   public void addAbteilungsleiter( Abteilungsleiter abteilungsleiter ) { abteilungsleiters.add( abteilungsleiter ); }
   public void removeAbteilungsleiter( ... ) { ... }
}
public class Abteilungsleiter extends Person {
   private List<Teamleiter> teamleiters = new ArrayList<...>();
   public void addTeamleiter( Teamleiter teamleiter ) { ... }
   ...
}
public class Teamleiter extends Person {
   // analog
}
public class Mitarbeiter extends Person {
}

2. Du kannst Generics verwenden, um das Komposite Muster auszulagern

Java:
public abstract class Leiter<U extends Person> extends Person {
   private List<U> untergeordnete = new ArrayList<U>();
   public void addUntergeordneten( U u ) { untergeordnete.add( u ); }
} 
public class Geschaeftsfuehrer extends Leiter<Abteilungsleiter> {
}
public class Abteilungsleiter extends Leiter<Teamleiter> {
}
...

Bei einer sehr festen Hierarchie wuerde ich zu Weg 1 tendieren (staerkere Typisierung, da addAbteilungsleiter Methoden existieren), aber Weg 2 ist mehr DRY (wobei man eine laengere Diskussion fuehren koennte, ob das in diesem Fall wirklich sinnvoll ist).

Man koennte die addUntergeordneten Methode auch protected machen und korrekt benannte (addAbteilungsleiter) Methoden diese einfach aufrufen lassen.
 

Mappenz

Bekanntes Mitglied
Das hört sich ja schon mal nach so etwas wie Zustimmung für mein bisheriges Vorgehen an :) . Der erste Vorschlag sieht sehr nach dem ursprünglichen Code aus. Ich muss mir mal ansehen ob das nicht schon solch eine Version des Kompositums war. Gibt es denn eine Erklärung, wesshalb ich nicht Funktionenen in meinem aktuellsten Code nicht contravariant überschreiben kann?
 

schalentier

Gesperrter Benutzer
Java:
boolean fuegeHinzu( Person a )
boolean fuegeHinzu( Abteilungsleiter a )
boolean fuegeHinzu( Teamleiter a )
boolean fuegeHinzu( Mitarbeiter a )

Das sind einfach vier unterschiedliche Methoden. Die kannst du natuerlich implementieren, aber nicht ueberschreiben. Man kann nur Methoden mit gleicher Signatur ueberschreiben und die genauen Argumenttypen gehoeren mit zur Signatur...
 

Mappenz

Bekanntes Mitglied
Oh, ja das stimmt natürlich. Das Substitutionsprinzip gilt natürlich für Funktionsaufrufe. Es ich denke dein aller letzter Vorschlag mach den Code am ehesten sauber.
 

Mappenz

Bekanntes Mitglied
Es ist nun vielleicht doch nötig die ganze Aufgabe zu posten.

Java:
import java.util.ArrayList;

public class Abteilungsleiter extends Person {
    ArrayList<Teamleiter> teamleiter = new ArrayList<Teamleiter>();

    public Abteilungsleiter(String vname, String nname) {
        super(vname, nname);
    }
    
    public void fuegeTeamleiterHinzu(Teamleiter tl) {
        teamleiter.add(tl);
    }
}

Java:
import java.util.ArrayList;

public class Teamleiter extends Person {
    ArrayList<Mitarbeiter> mitarbeiter = new ArrayList<Mitarbeiter>();
    
    public Teamleiter(String vname, String nname) {
        super(vname, nname);
    }

    public void fuegeMitarbeiterHinzu(Mitarbeiter m) {
        mitarbeiter.add(m);
    }
}

Java:
public class Person {
    // bei uns verdienen erst einmal alle gleich viel ...
    public int gehalt = 42;
    public String vorname;
    public String nachname;
    
    public Person(String vname, String nname) {
        vorname = vname;
        nachname = nname;
    }
    
    public String gibName() {
        return vorname + " " + nachname;
    }
}

Java:
public class Mitarbeiter extends Person {

    public Mitarbeiter(String vname, String nname) {
        super(vname, nname);
    }import java.util.ArrayList;

/* Der Geschäftsführer ist der (einzige) oberste Chef der Firma. */
public class Geschaeftsfuehrer extends Person {
    ArrayList<Abteilungsleiter> abteilungsleiter = new ArrayList<Abteilungsleiter>();

    public Geschaeftsfuehrer(String vname, String nname) {
        super(vname, nname);
    }

    public void fuegeAbtLeiterHinzu(Abteilungsleiter al) {
        abteilungsleiter.add(al);
    }
}
}

Java:
public class Firma {
    public String firmenname;
    public Geschaeftsfuehrer gf;

    /**
     * @param args Kommandozeilenargumente
     */
    public static void main(String[] args) {
        // Erstelle die Firma
        Geschaeftsfuehrer gf = new Geschaeftsfuehrer("Walter", "Tichy");
        Firma f = new Firma("Entwurfsmuster GmbH", gf);

        // Statte den Geschäftsführer mit Abteilungsleitern aus
        Abteilungsleiter al1 = new Abteilungsleiter("Victor", "Pankratius");
        gf.fuegeAbtLeiterHinzu(al1);
        Abteilungsleiter al2 = new Abteilungsleiter("Ali", "Jannesari");
        gf.fuegeAbtLeiterHinzu(al2);

        // Gib den Abteilungsleitern ein paar Teamleiter
        // Pankratius
        Teamleiter tl1 = new Teamleiter("Frank", "Otto");
        al1.fuegeTeamleiterHinzu(tl1);
        Teamleiter tl2 = new Teamleiter("Jochen", "Schimmel");
        al1.fuegeTeamleiterHinzu(tl2);

        // Jannesari
        Teamleiter tl3 = new Teamleiter("Andreas", "Höfer");
        al2.fuegeTeamleiterHinzu(tl3);
        Teamleiter tl4 = new Teamleiter("Sven", "Körner");
        al2.fuegeTeamleiterHinzu(tl4);

        // und manchen Teamleitern ein paar Mitarbeiter
        Mitarbeiter m1 = new Mitarbeiter("Max", "Udri");
        tl1.fuegeMitarbeiterHinzu(m1);

        Mitarbeiter m2 = new Mitarbeiter("Ihssane", "El-Oudghiri");
        tl2.fuegeMitarbeiterHinzu(m2);

        // und nun gib mir die Hierarchie aus
        f.gibHierarchieAus();
    }

    public Firma(String firmenname, Geschaeftsfuehrer gf) {
        this.firmenname = firmenname;
        this.gf = gf;
    }

    public void gibHierarchieAus() {
        System.out.println("|-- Geschäftsführer: " + gf.gibName());
        for (Abteilungsleiter al : gf.abteilungsleiter) {
            System.out.println("  |-- Abteilungsleiter: " + al.gibName());
            for (Teamleiter tl : al.teamleiter) {
                System.out.println("    |-- Teamleiter: " + tl.gibName());
                for (Mitarbeiter m : tl.mitarbeiter) {
                    System.out.println("      |-- Mitarbeiter: " + m.gibName());
                }
            }
        }
    }

}

Das ist der Code der mit der Aufgabe mitgeliefert wurde. Der relevante Teil des Aufgabentextes liest sich so:

Bauen Sie den darin enthaltenen Quelltext um. Verwenden Sie dazu ein Entwurfsmuster, das Ihnen zur Lösung der Aufgabe geeignet erscheint.
Fassen Sie keine Teile des Quelltextes an, die durch entsprechende Kommentare geschützt sind.
Analysieren Sie, was das bestehende Programm tut.
Wählen Sie ein Entwurfsmuster aus, das sich zur Lösung bzw. Verschönerung des Quelltextes eignet.

Ist in diesem Code das Muster Kompositum nicht schon in der von schalentier vorgeschlagenen Variante enthalten? Was bleibt denn jetzt noch zu tun?
 

Ähnliche Java Themen

Neue Themen


Oben