Composite, Design Pattern, printTree

Status
Nicht offen für weitere Antworten.

guni

Bekanntes Mitglied
Hi,

bin neu in Java und habe aus gg. Anlass heraus probiert, ein Composite-Design-Pattern auszuprogrammieren ...

dabei habe ich
* eine abstrakte Klasse Tree von der sich
* 2 Klassen ableiten: Folder und File

das ganze soll darauf hinauslaufen, dass ich eine hierachische Baumstruktur aufbauen will.
Jetzt will ich in der Basisklasse eine Methode printTree schreiben, die von gegebenem Element weg den Verzeichnisbaum ausgibt.
Aber irgendwie bring ich das Ganze nicht so auf die Reihe, wie ich es mir erhoffen würde.
Das Problem: ich könnte das Ganze theoretisch rekursiv lösen, aber die tatsächlichen Elemente des Verzeichnisbaumes werden im Echteinsatz mal aus der Datenbank ausgelesen und da werd ich warscheinlich mehrere 10.000 Elemente haben ... das könnte mir rekursiv irgendwann einen Stack-Overflow geben ...

also, könnt ihr mir ein bisschen auf die Sprünge helfen wie ich eine prtinTree mit Schleifen ausprogrammieren könnte?
mein Strukturmuster verwendet einen ListIterator um den Tree aufzubauen.

lg, guni
 
S

SlaterB

Gast
10.000 Elemente ist erstmal nicht schlimm,
bei einem binären Baum (jeder Knoten hat zwei Nachfolger) wäre das ja offensichtlich nur eine Tiefe von 14,
bei noch breiteren Bäumen siehts noch besser aus,

oder hast du einen verrückten Baum mit tausenden Elementen untereinander?

die Alternative zu Rekursion ist jedenfalls eine Liste aller noch offenen Knoten,
aus der nimmst du jeweils einen raus, holst dir dessen Kindern und packst diese auch in die Liste, mehr ist das kaum
 

guni

Bekanntes Mitglied
hmm ... tiefe von 14 - ok.
bis zu welcher tiefe würdest du rekursionen denn emfehlen?
wenn ich eine Tiefe von 20 hätte, könnt ich ja schon über eine Million Elemente darstellen :D
(bei einem binären Baum !!!)

aber wer sagt, dass mein Baum binär ist? Wenn es so wäre, dann würde ich da was falsch verstehen weil ein Ordner in einem Verzeichnis (Knoten) kann ja mehr als 2 Unterverzeichnisse aufnehmen (mehr als 2 Nachfolger!)

hast du das gemeint, wo du von einem breiteren Baum gesprochen hast?
Dass dei Elemente nicht so tief verschachtelt werden sondern eher in der Ebene bleiben?
Die Rekursion hat in der Ebene keine Auswirkungen auf Speicherbelastung, oder? Nur in der Ebenentiefe!
Oder versteh ich da wieder was falsch??

lg, guni

PS.:
* wie würde eine Rekursion für sowas ansatzweise aussehen? ich hab da immer einen stack-overflow-error gehabt!
* wie kann ich die ebenentiefe ermitteln? (= meine Einrückung)
* gibt es in Java eine Funktion, die mir eine bestimmte anzahl von Leerzeichen vor einen String schreibt oder muss ich mir sowas selber schreiben?
* das parent-element kann ich schon mit übergeben, oder ;-)
 
S

SlaterB

Gast
> bis zu welcher tiefe würdest du rekursionen denn emfehlen?

unter 1000

> aber wer sagt, dass mein Baum binär ist?

das ist nur der Worst-Case unter den normalen Bäumen, deiner ist wohl breiter ja, dann ist es noch besser

> Die Rekursion hat in der Ebene keine Auswirkungen auf Speicherbelastung, oder?

wenn man sie richtig baut, ja

> wie würde eine Rekursion für sowas ansatzweise aussehen?

was willst du übrhaupt bauen?
ganz normal wäre z.B.

String beschreibung = "";
beschreibung += (Beschreibung für aktuellen Knoten);
for (alle Kinder) {
beschreibung += (rekursiver Aufruf für Kind);
}

bei 1000 Elementen allerdings besser nicht Strings addieren,
sondern alles in einem StringBuilder einfügen, der als Parameter herumgereicht wird

> wie kann ich die ebenentiefe ermitteln?

auch per Rekursion

int tiefe = 1 + übergebene Tiefe;
int maxTiefe = tiefe;
for (alle Kinder) {
maxTiefe = max(rekursiver Aufruf für Kind mit tiefe als Parameter);
}

> gibt es in Java eine Funktion, die mir eine bestimmte anzahl von Leerzeichen vor einen String schreibt oder muss ich mir sowas selber schreiben?

denke nicht

> das parent-element kann ich schon mit übergeben, oder

mach was du für richtig hälst,
aber: jeder Parameter füllt den StackTrace etwas mehr und verrngert die mögliche Rekursionstiefe :bae:
 

guni

Bekanntes Mitglied
was willst du übrhaupt bauen?

ich denke es ist an der Zeit, mal ein bisschen code zu posten :)

also: hier meine basisklasse:

Code:
package structural.composite;

import java.util.LinkedList;
import java.util.ListIterator;

@SuppressWarnings("unchecked")
public abstract class Tree {
	LinkedList TreeList; 
	Tree parent;
	String name;
	
	public abstract boolean add(Tree itemToAdd);
	public abstract boolean remove(Tree itemToRemove);
	public abstract ListIterator createListIterator();
	
	public void setParent(Tree parentIn) {
		parent = parentIn;
	}	
	public Tree getParent() {
		return parent;
	}
	public void setName(String nameIn) {
		name = nameIn;
	}
	
	public String getName() {
		return name;
	}
	
	public void printTree(Tree parent){
		// DAS WILL ICH BAUEN!!! 
		// KEINE AHNUNG WIE DAS GEHEN SOLL! MIR FEHLT VOLL DER ANSATZ!
	}

}

dazu gibt es eine abgeleitete Klasse Folder:

Code:
package structural.composite;

import java.util.LinkedList;
import java.util.ListIterator;

@SuppressWarnings("unchecked")
public class Folder extends Tree {

	public Folder(String nameIn){
		TreeList = new LinkedList();
		this.setName(nameIn);
	}
	
	@Override
	public boolean add(Tree itemToAdd) {
		itemToAdd.setParent(this);
		return TreeList.add(itemToAdd);
	}

	@Override
	public ListIterator createListIterator() {
		ListIterator listIterator = TreeList.listIterator();
		return listIterator;
	}

	@Override
	public boolean remove(Tree itemToRemove) {
		ListIterator listIterator = this.createListIterator();
		Tree tempTree;
		while (listIterator.hasNext()) {
			tempTree = (Tree)listIterator.next();
			if (tempTree == itemToRemove) {
               listIterator.remove();
               return true;
           }
       }
       return false;
	}

}

... und dann noch eine Klasse Link (= File)

Code:
package structural.composite;

import java.util.ListIterator;

@SuppressWarnings("unchecked")
public class Link extends Tree {
	String LinksTo;
	
	public Link(String nameIn) {
		this.setName(nameIn);
	}
	
	public boolean addReference(String linkIn){
		this.LinksTo = linkIn;
		return true;
	}

	@Override
	public boolean add(Tree itemToAdd) {
		return false;
	}

	@Override
	public ListIterator createListIterator() {
		return null;
	}

	@Override
	public boolean remove(Tree itemToRemove) {
		return false;
	} 

}

mein Main Programm könnte dann (in der 1. Entwicklungsstufe circa das hier:

Code:
package mainapp;

import structural.composite.*;
@SuppressWarnings("unchecked")
public class CompanyHierachy {

	public static void main(String[] args){
		
		Folder root = new Folder("lsalarchiv");
		Folder Firma1 = new Folder("Firma1");
		Folder Firma2 = new Folder("Firma2");
		Folder AbtA = new Folder("Abteilung A");
		Folder AbtB = new Folder("Abteilung B");
		Folder AbtC = new Folder("Abteilung C");
		Folder AbtD = new Folder("Abteilung D");
		Folder AbtE = new Folder("Abteilung E");
		Folder AbtF = new Folder("Abteilung F");
		
		root.add(Firma1);
		root.add(Firma2);
		
		Firma1.add(AbtA);
		Firma1.add(AbtB);
		Firma1.add(AbtC);
		Firma1.add(AbtD);
		Firma2.add(AbtE);
		Firma2.add(AbtF);
		
		
		root.printTree(root);
	}

}

das problem:
ich häng an der rekursion.

mir fehlt voll der ansatz!!!
konzeptionell gesehen würde es ja auch reichen, wenn sie in der basisklasse noch gar nicht aufscheint, sondern 'nur' auf ordnerebene, oder?! eine datei kann ja eh keine children haben! andererseits sollen dateien genauso mit ausgegeben werden!

könnt ihr mir helfen?

lg, guni
 
S

SlaterB

Gast
ich zumindest habe dir das Konzept erstellt,
wenn dir dazu nix einfällt, weiß ich nicht, was ich weiter erzählen soll,

kennst du dich denn mit einfacheren Rekursionen aus?
z.B. Fakultät rekursiv berechnen, eine LinkedList rekursiv durchlaufen?
 
M

maki

Gast
Das Prblem mit rekursio ist, dass sie durch die Anzahl der Stackframes begrenzt wird, dann bekommst du deinen Fehler.
Als Alternative kommt iteration in Frage, am besten wenn man so etwas wie eine Stack-Collection verwendet.

Werd nachher mal Googeln, vielleicht findet sich ein Beispiel.
 

guni

Bekanntes Mitglied
@SlaterB:
fakultät ja, linkedList durchlaufen nein - aber genau darum geht es ja, oder?!?!
@maki:
würdest du eher schleifen empfehlen. ich denke nicht, dass ich jemals eine rekursionstiefe von 1000 überschreiten werde ...
 

guni

Bekanntes Mitglied
@SlaterB ...

mit dem DesignPattern habe ich ja praktisch eine LinkedList, die aus genau solchen Listen besteht ...
 
M

maki

Gast
würdest du eher schleifen empfehlen. ich denke nicht, dass ich jemals eine rekursionstiefe von 1000 überschreiten werde ..
Dann kannst du dir die Iterative Lösung ersparen.

Hier mein Tipp:
Benutze das Visitor Pattern :)

Erzeuge zwei interfaces,

1. Visitor
Code:
public interface Visitor{
	public boolean visit(Tree host);	
}

2. Visitable
Code:
public interface Visitable{
	public void accept(Visitor Visitor);
}

Lass deinen Tree das Visitable Interface implementieren, sollte in etwa so aussehen:
Code:
public abstract class Tree 
implements Visitable{
...
    public void accept(Visitor visitor) {
        if (nodeVisitor.visit(this) == true) {
            for (Tree child : TreeList )
                child.accept(visitor);
            }
        }
    }
...
}
Sobald der Visitor false zurückgibt, wird die rekursive Verarbeitung abgebrochen.

Solltest imho dafür sorgen, dass Tree als "Kinder" nur Trees enthalten kann, denn darum geht es beim Kompositium/Composite, d.h. Typisierte Listen, dann sparst du dir auch das ignorieren der unchecked Warnings.

Der Visitor hat nun die Logik, ein Beispiel:
Code:
public class ExampleVisitor 
implements Visitor {

        public boolean visit(Tree host) {
            // hier kommt deine Logik die was mit den einzelnen Trees macht

            // Abfrage, ob das maximumlevel schon erreicht ist
            if(currentLevel >= maxLevel) {
                return false;
            } else {
                return true;
            }

        }
}

Aufruf mit:
Code:
Tree myTree = new .....
Visitor myVisitor = new ExampleVisitor();
...
myTree.accept(myVisitor);
So in etwa ;)

Kannst beliebig viele Visitor erstellen und so Funktonalität hinzufügen, ohne die Klassen zu verändern, machst einfach weitere Visitorimplementierungen.
Wie du siehst funktonieren Pattern am besten im Verbund.
 
S

SlaterB

Gast
> aber genau darum geht es ja, oder?!?!

hier könnte es schwieriger sein, weil du mehrere Richtungen verfolgen musst,

machen wir es noch einfacher,
du hast ein Objekt der Klasse A und eines der Klasse B,
B ist in A enthalten, in A hast du eine Ausgabeoperion die alles von A und B ausgeben soll, wie machst du das?

Code:
public class Test
{

    public static void main(String[] args)
        throws Exception
    {
        A a = new A();
        System.out.println(a); // Ausgabe "a, b"?
    }
}


class A
{
    String name = "a";
    B b = new B();

    public String toString()
    {
        return name;
    }
}


class B
{
    String name = "b";

    public String toString()
    {
        return name;
    }
}
 

jPat

Bekanntes Mitglied
Evtl. möchtest du es ja so haben:

Code:
   public void printTree(Tree parent,String s){
	   for ( Object o : parent.TreeList){
		   if (o instanceof Folder) {
			   System.out.println(s+"(F) "+o);
			   ((Folder)o).printTree((Tree)o, s+"-");
		   }
		   if (o instanceof Link) {
			   System.out.println(s+"(L) "+o);
		   }	   
	   }
   }
   @Override
   public String toString() {
	   // TODO Auto-generated method stub
	   return name;
   }

[EDIT] nun auch mit eine Strukturierten Ausgabe. Aufruf: root.printTree(root,"");
 

guni

Bekanntes Mitglied
@slater:

1. ich versteh nicht ganz, was das Beispiel mit meinem Problem zu tun hat.

2. kenn ich mich zu wenig in Java aus um zu verstehen, wie das funktioniert, da meiner Meinung nach ein Fehler hätte auftreten müssen. Du schreibst
Code:
System.out.println(a);
a ist ein Objekt! Es besteht aus Attributen und Methode(n) - woher aber weiß printf, was es ausgeben soll!

ich glaube, dass man diese Frage beantworten muss um zu wissen, wieso da was ausgegeben wird.

abgesehen davon versteh ich nicht, wieso ich da etwas in mehrere richtungen verfolgen muss!
vielleicht habe ich mein problem falsch dargestellt:

printTree soll eine METHODE sein!
Nach oben hin interessiert mich der Baum gar nicht mehr.
ich lege ein root-Objekt an und dann sag ich einfach
Code:
root.printTree();
wenn das ganze von einem Unterknoten aufgerufen wird, dann wird der Tree eben erst ab dem Unterknoten angezeigt!

die Funktion soll ungefähr das tun:

durchsuche alle Unterverzeichnisse/Datein und gib sie solange aus, bis du nix mehr findest.

meine 1. große Frage bei der Rekursion wäre: was ist die Abbruchbedingung???

In meinem obenstehenden Beispiel sollte die Fkt. folgendes ausgeben:

lsalarchiv
lsalarchiv/Firma1
lsalarchiv/Firma1/Abteilung A
lsalarchiv/Firma1/Abteilung B
lsalarchiv/Firma1/Abteilung C
lsalarchiv/Firma1/Abteilung D
lsalarchiv/Firma2
lsalarchiv/Firma2/Abteilung E
lsalarchiv/Firma2//Abteilung F

wie kann ich das lösen? ist das wirklich so schwer? ich dachte, ich bring es einfach nur deswegen nicht zsamm, weil ich
A) mich nicht soo gut mit Rekursionen auskenne
B) ich neu in Java bin

aber es wirkt, als wäre die Sache schon etwas komplexer, oder?!

lg, guni
 

jPat

Bekanntes Mitglied
Was heist hier komplexer :lol:

Code:
   public void printTree(Tree parent,String s){
	   for ( Object o : parent.TreeList){
		   if (o instanceof Folder) {
			   System.out.println(s+"/"+o);
			   ((Folder)o).printTree((Tree)o, s+"/"+o);
		   }
		   if (o instanceof Link) {
			   System.out.println(s+"/"+o);
		   }	   
	   }
   }
   @Override
   public String toString() {
	   // TODO Auto-generated method stub
	   return name;
   }

Ohh, wie Komplex! :D
 
S

SlaterB

Gast
> ich versteh nicht ganz, was das Beispiel mit meinem Problem zu tun hat.

es lehrt, Rekursion zu erlernen (hoffe ich zumindest ;) )

> woher aber weiß printf, was es ausgeben soll!

nun gut, das muss man einmal wissen: es wird bei Objekten deren toString()-Operation aufgerufen,

> versteh ich nicht, wieso ich da etwas in mehrere richtungen verfolgen muss!

wenn du nur weniger Richtungen siehst, umso besser,
ich will nur sagen, dass eine lineare Liste doch einfacher aufgebaut ist als ein verzweigter Baum,
dass in einer Liste die Rekursion deutlicher ist

> was ist die Abbruchbedingung???

wenn ein Knoten keine Kinder hat, dann die Operation nicht rekursiv für die nichtvorhandenen Kinder aufrufen ;)
in diesem Fall also trivial

> ist das wirklich so schwer?
> aber es wirkt, als wäre die Sache schon etwas komplexer, oder?!

nein, ist machbar, aber für dich anscheinend schwer
 

guni

Bekanntes Mitglied
FREAK!!!! :toll:

just to get this straight:

Code:
for ( Object o : parent.TreeList)
damit durchlaufe ich die Liste des Objects, für die ich den Code aufrufe, oder?!
und damit habe ich dann auch immer eine Abbruchbedingung.

verstehe ich das richtig?!?!

danke jedenfalls!
das scheint zu funktionieren; d.h. ich kann mich auf die DB stürzen :D

lg, guni
 

guni

Bekanntes Mitglied
ok ... und welche vorteile habe ich jetzt, wenn ich statt einer simplen rekursion ein visitor-pattern ausprogrammiere?!

lg, guni
 

guni

Bekanntes Mitglied
okay ... nochmal zu meiner Frage:

ich habe eine Baumdarstellung, die ich als Composite gelöst habe.
Die Idee:
eine abstrakte Klasse,
die ihre Methoden an 2 Subklassen (Ordner und Datei) vererbt.

der Vorteil: printTree ist eine Methode, die ich in der Basisklasse erstellen kann!
sie ist unabhängig von den Subklassen!

jetzt bekomme ich den Vorschlag, noch ein Visitor-Muster zu realisieren.
Es hat den Vorteil, dass man einen Algorithmus vom Objekt trennen kann ...
also aus einer Objektmethode eine allgemeine Funktion machen kann.

Nur seh ich nicht den Sinn dahinter!
Wenn ich eine allgemeine Funktion machen will, dann schreib ich sie doch einfach in meine Hauptklasse und ruf sie in der main-funktion auf!!!

und was bringt mir ein visitor muster im bezug auf die darstellung einer Ordnerstruktur?! Wenn ich ein Composite habe, dann habe ich meine allgemeinen Funktionen doch sowieso in der abstrakten klasse!!!!!! wozu soll ich also noch ein Muster anlegen?!

lg, guni
 
M

maki

Gast
Composite tritt fast nur mit Visitor auf, die beiden gehören zusammen weil sie sich so gut ergänzen.

Wenn ich eine allgemeine Funktion machen will, dann schreib ich sie doch einfach in meine Hauptklasse und ruf sie in der main-funktion auf!!!
Scherzkeks *g*

Visitor kann mehr als nur allgemeine Funktionen, es kann auch spezialisierte Funktionen anbieten.

Du müsstest jedesmal deine Tree Klasse ändern um funktionen hinzuzufügen, mit dem Visitor schreibst du dir einfach deinen eigenen speziellen Visitor, die Tree Klasse ändert sich nicht.

Abgesehen davon ist der Visitor wirklich simpel, 2 Interfaces, hab ich dir schon geschrieben, C&P reicht.
Die Implementierung der Visitable Interfaces kann so auch stehenbleiben, du musst nur diene Funktionen in den Visitor schreiben.

Wenn dir printTree als einzige Funktion reicht, brauchst du keinen Visitor, wenn du jetzt noch suchen, kopieren, eine spezielle printTree Funktion etc. möchtest, ist Visitor den Freund.
 

guni

Bekanntes Mitglied
@manki ...

hmm - du bringst mich da auf ideen ....
vielleicht werde ich das doch mal angehn.
ich werd mal kurz schaun, was ein interface eigentlich ist, da ich erst seit 1 woche java mach und vorher nicht wirklich objektorientiert programmiert hab :D

lg, guni
 

guni

Bekanntes Mitglied
nana - passt schon.
vom konzept her war mir das ganze schon klar.
ich bin halt vorher ziemlich auf perl abgefahrn (linguistisch gesehn is es viel romantischer) aber da perl VOR der objektorierentierung entwicklet worden ist und sich diese Freaks vorgenommen haben die uralten compiler für neuen code kompatibel zu halten ist die objektorientierung etwas ... sagen wir mal: rudimentär.

vererbung, interfaces und so zeug mach ich jetzt eben parktisch erst mit java ...
aber es geht eh voran :D
dank dem forum lern ich recht schnell und für das, dass ich vor einer woche noch nie java programmiert habe geht es eigentlich schon ganz flüssig von der hand *gg*

lg, guni
 

guni

Bekanntes Mitglied
@maki:
du schreibst:
Solltest imho dafür sorgen, dass Tree als "Kinder" nur Trees enthalten kann, denn darum geht es beim Kompositium/Composite, d.h. Typisierte Listen, dann sparst du dir auch das ignorieren der unchecked Warnings.

das macht ja keinen Sinn! Schön, wenn das Composite-Muster das in seiner Philosophie vorsieht aber in der Praxis kann ich in eined Dateistruktur ja sowohl das Element Ordner als auch das Element Datei in einem Ordner haben!
Wie soll ich dass denn mit einer typisierten Liste lösen?!?

lg, guni
 
M

maki

Gast
Sowohl Datei als auch Ordner sollten eine gemeinsame Oberklasse haben, darum geht es beim Composite.
D.h. dein Typ sollte Tree sein, auch wenn ich diese Namensgebung etwas missglückt empfinde.
 

guni

Bekanntes Mitglied
Sowohl Datei als auch Ordner sollten eine gemeinsame Oberklasse haben
das haben sie ja!
deine Aussage war aber - wenn ich das richtig verstanden habe - dass man gegen die Philosophie vom Composite verstößt, wenn man Datei-Objekte und Ordner-Objekte in die gleiche Liste speichert. Und da stellt sich mir die Frage: gibt es da eine schönere Möglichkeit?
auch wenn ich diese Namensgebung etwas missglückt empfinde
ja - ich weiß auch, dass der Name nicht wirklich das aussagt um das es geht!
mir is auf die gschwinde nix anderes eingfalln - hast an besseren vorschlag? ich bin für jede idee offen. außerdem kann ich dann gleich mal die Refactoring-Funktion von Eclipse wieder mal gut ausprobieren :D

lg, guni
 
M

maki

Gast
deine Aussage war aber - wenn ich das richtig verstanden habe - dass man gegen die Philosophie vom Composite verstößt, wenn man Datei-Objekte und Ordner-Objekte in die gleiche Liste speichert. Und da stellt sich mir die Frage: gibt es da eine schönere Möglichkeit?
Dann habe ich mich unklar ausgedrückt, die Listen sollten <Tree> enthalten.

Als Namen würde ich Node (Knoten) empfehlen, ist aber geschmackssache.
 

guni

Bekanntes Mitglied
danke für die Antwort.

habe jetzt gleich mal alles auf Node geändert - triffts einfach besser :D

du schreibst:
Dann habe ich mich unklar ausgedrückt, die Listen sollten <Tree> enthalten.
(inzwischen ist das ja <Node> *gg*)
Jedenfalls kann ich den Listen gar nicht <Node> zuweisen, weil ich ja eine Liste von Objekten habe und <Node> ja eine abstrakte Klasse Klasse ist, von der sich die beiden Klassen Folder und File ableiten. Und ich kann ja - wenn ich das richtig verstanden habe - nur aus nicht-abstrakten Klassen Objekte erstellen, oder?!
Das war ja eigentlich auch irgendwie der Sinn des Composites, dass man verschiedne Objekte in eine Struktur packt, die ähnlich aber eben doch nicht gleich sind ... oder versteh ich da was falsch?
Wie also soll ich <Node>-Objekte in meine Liste packen, das geht ja gar nicht!

zu deinem Code von Seite 1:

ich hab jetzt mal versucht, den Visitor ganz einfach zu realisieren.
Nach meinem Verständnis ist er ja ungefähr so aufgebaut:

auf "abstrakter ebene" gibt es 2 interfaces: visitor und visitable.
bei visitor hab ich eine methode visit drin, bei visitable hab ich eine funktion accept drin
als nächstes sag ich, dass meine node-klasse visitable implementiert und programmier die funktion accept dort aus.
dann schreib ich konkrete Visitorklassen (z.B.: PrintTree) die den abstrakten Visitor implementieren und sag dort dann, dass - in meinem Beispiel - der ganze Baum ausgegeben werden soll ...

in deiner Accept-Funktion schreibst du jetzt in Zeile 2 nodeVisitor ... und ich steh schon wieder voll auf der Leitung. Wer is mein nodeVisitor? Muss da nicht this rein? wo leg ich den nodeVisitor fest? Was muss da in meinem Fall wirklich stehen?

Code:
public void accept(Visitor visitor) {
    if (nodeVisitor.visit(this) == true) {
        for (Tree child : TreeList )
            child.accept(visitor);
        }
    }
}

lg, guni
 
M

maki

Gast
Die LinkedList sollte eigentlich typisiert sein, LinkedList<Node> eben.
Das geht, der Polymorphie sei dank ;)

NodeVisitor war meine Klasse, das Objekt habe ich deshalb nodeVisitor genannt (in Java schreibt man Variablen immer klein), bei dir wäre das visitor.

Über den Rückgabewert boolean kann man der accept Methode mitteilen, wann genug Nodes besucht wurden.

Die accept Methode ruft die visit Methode des Visitors auf, mit this als Parameter.
Das machen rekursiv alle Nodes, bis false zurückgegeben wird oder es keine Kinder mehr gibt.

Solltest den Unterschied zwischen Interfaces und abstrakten Klassen schon verstehen, ist wichtig.
Ich nehme an, du hast ein gutes Buch über Java.
 

guni

Bekanntes Mitglied
Ich nehme an, du hast ein gutes Buch über Java.
nope - ich bezieh derzeit mein ganzes wissen aus dem gespräch mit dir :D

aber den unterschied habe ich, denke ich schon verstanden - so rein aus dem anwendungkontext heraus:

die abstrakte klasse ist eine klasse, von der keine objekte erzeugt werden können; sie kann nur als Basisklasse für die Weitervererbung dienen

ein interface ist eine sammlung von methoden, die erst in einer klasse ausprogrammiert werden.

der unterschied ist vermutlich, dass eine abstrakte klasse doch schon mehr form hat wie ein interface ... schließlich gibt sie ja schon attribute mit, kann auch schon private methoden oder sogar ausprogrammierte public methoden enthalten; wenn sie all das nicht hat kann ich ja gleich wieder ein interface schreiben, oder :D

habe meine funktion inzwischen fertiggestellt :D

im Endeffekt schaut mein Konkreter Visitor jetzt so aus:
Code:
public class PrintTree implements Visitor {

	public boolean visit(Node host, String hostname) {
		for ( Object o : host.nodes){
			if (o instanceof Folder) {
				System.out.println(hostname+"/"+((Folder)o).getName());
				visit((Node)o, hostname+"/"+((Folder)o).getName());
			}
			if (o instanceof Link) {
				System.out.println(hostname+"/"+((Link)o).getName());
			}      
		}
		return false;
	}

}
wie ich allerdings meine Listen typisieren kann check ich noch immer nicht ...
meine int main schaut jetzt so aus:
Code:
public static void main(String[] args) throws SQLException, ClassNotFoundException{
	
	// visitForPrinting.visit(root);
	PrintTree visitForPrinting = new PrintTree();
	Folder root = new Folder("lsalarchiv");
	
	Folder Firma1 = new Folder("Firma1");
	Folder Firma2 = new Folder("Firma2");
	Folder AbtA = new Folder("Abteilung A");
	Folder AbtB = new Folder("Abteilung B");
	Folder AbtC = new Folder("Abteilung C");
	Folder AbtD = new Folder("Abteilung D");
	Folder AbtE = new Folder("Abteilung E");
	Folder AbtF = new Folder("Abteilung F");
	
	Link EmpA = new Link("Mitarbeiter A");
	Link EmpB = new Link("Mitarbeiter B");
	Link EmpC = new Link("Mitarbeiter C");
	Link EmpD = new Link("Mitarbeiter D");
	Link EmpE = new Link("Mitarbeiter E");
	Link EmpF = new Link("Mitarbeiter F");
	Link EmpG = new Link("Mitarbeiter G");
	Link EmpH = new Link("Mitarbeiter H");
	Link EmpI = new Link("Mitarbeiter I");
	Link EmpJ = new Link("Mitarbeiter J");
	Link EmpK = new Link("Mitarbeiter K");
	Link EmpL = new Link("Mitarbeiter L");
	Link EmpM = new Link("Mitarbeiter M");
	
	root.add(Firma1);
	root.add(Firma2);
	
	Firma1.add(AbtA);
	Firma1.add(AbtB);
	Firma1.add(AbtC);
	Firma1.add(AbtD);
	Firma2.add(AbtE);
	Firma2.add(AbtF);
	
	AbtA.add(EmpA);
	AbtA.add(EmpB);
	AbtA.add(EmpC);
	AbtB.add(EmpD);
	AbtB.add(EmpE);
	AbtB.add(EmpF);
	AbtC.add(EmpG);
	AbtC.add(EmpH);
	AbtC.add(EmpI);
	AbtE.add(EmpJ);
	AbtE.add(EmpK);
	AbtE.add(EmpL);
	AbtF.add(EmpM);
	
	root.accept(visitForPrinting);
	// Firma1.showMyContent();
	
	// root.printTree(root,root.getName());
	// createBaseStructure();	
}
da kann ich doch nicht Objekte von einer abstrakten Klasse erstellen!
deswegen sind meine Objekte immer Folder oder Links!!

wie kann ich also meine Listen typisieren?
lg, guni
 
M

maki

Gast
die abstrakte klasse ist eine klasse, von der keine objekte erzeugt werden können; sie kann nur als Basisklasse für die Weitervererbung dienen

ein interface ist eine sammlung von methoden, die erst in einer klasse ausprogrammiert werden.
In Java können Objekte nur von einer einzigen Klasse erben, aber so viele Interfaces implementieren wie sie möchten.
Wenn man "extends" sagt, mein man "ist ein", während man bei Interfaces, also "implements", ausdrückt, dass eine Klasse etwas kann.

im Endeffekt schaut mein Konkreter Visitor jetzt so aus:
....
Wozu schleifen?
Die visit Methode wird von jeder Node aufgerufen, rekursiv ;)
Lass das for mal weg, aber dann musst du natürlich auch true zurückgeben.

Den Sinn des hostname Parameters verstehe ich nicht ganz.

wie ich allerdings meine Listen typisieren kann check ich noch immer nicht ...
meine int main schaut jetzt so aus:
Zeig doch mal deine aktuelle Node Klasse.
 

guni

Bekanntes Mitglied
Den Sinn des hostname Parameters verstehe ich nicht ganz.
den hostname-parameter habe ich eingebaut um den Namen meines Root-Folders mitzuübergeben ...
Zeig doch mal deine aktuelle Node Klasse.
meine aktuelle Node-Klasse sieht so aus:
Code:
package pattern.structural.composite;

import java.util.LinkedList;
import java.util.ListIterator;
import pattern.behavioral.visitor.Visitable;
import pattern.behavioral.visitor.Visitor;

@SuppressWarnings("unchecked")
public abstract class Node 
implements Visitable{
	public LinkedList nodes; 
	Node parent;
	String name;
	
	public abstract boolean add(Node itemToAdd);
	public abstract boolean remove(Node itemToRemove);
	public abstract ListIterator createListIterator();

	public void accept(Visitor operation) {
		if (operation.visit(this,this.getName()) == true) {
			for (Object child : nodes)
				((Node)child).accept(operation);
		}
	}
	
	public void setParent(Node parentIn) {
		parent = parentIn;
	}	
	public Node getParent() {
		return parent;
	}
	public void setName(String nameIn) {
		name = nameIn;
	}
	
	public String getName() {
		return name;
	}
	
	public boolean NodeExists(String inName){
		ListIterator i = this.createListIterator();
		Node element;
		Boolean found = false;
		while (i.hasNext()){
			element = (Node)i.next();
			if (element.getName().equals(inName))
				found = true;
		}
		return found;
	}
	
	public void showMyContent(){
		ListIterator listIterator = this.createListIterator();
		Node currentTree;
		while (listIterator.hasNext()){
			currentTree = (Node)listIterator.next();
			System.out.println(currentTree.getName());
		}
	}
}
lg, guni
 
M

maki

Gast
Das hier zB
Code:
public LinkedList nodes;
sollte so aussehen:
Code:
public LinkedList<Node> nodes;
So weis der Compiler, dass deine Liste nur Nodes enthalten darf.

Das gleiche gilt für alle Stellen, an denen du List oder LinkedList verwendest.

Deine Anno die die unchecked warnings unterdrückt solltest du rauswerfen.
 

guni

Bekanntes Mitglied
danke ...

habe jetzt übrigens auch deinen Rat befolgt und die konkrete Visit-Methode umgeschrieben.
da - wie du gesagt hast - eh jeder Knoten rekursiv besucht wird habe ich die schleife und alles rausgenommen und nur mehr eine Funktion der Form:
Code:
public boolean visit(Node host) {
	System.out.println(host.getName());
	if (host instanceof Folder){
		return true;
	} else {
		return false;
	}
}
vorher hat das viel komplizierter ausgesehn ... jetzt verstehe ich auch den Visitor wieder ein Stückchen mehr weil ich die Rekursion nur einmal lösen musste und in die konkreten Visit-Funktionen eigentlich nur die Logik reinschreiben muss, die den jeweiligen Knoten betrifft.

Was ich aber noch nicht ganz verstehe ist, wie ich jetzt in meine obenstehende Funktion wieder einbau, dass zu jedem Host immer der ganze Pfad ausgegeben wird ...

lg, guni

PS.: deinen Tipp mit der Node werd ich gleich umsetzten!
 
M

maki

Gast
Vielleicht gibt es eine Möglichkeit, dass du den doofen instanceOf operator loswirst ;) Polymorphie ist zu bevorzugen wo möglich.

Um den Pfad kümmern wir uns später, als Tipp: Du kannst doch in einer Schleife die Parents abfragen und deren Pfad so bekommen, zwar nciht performant, aber ne bessere Schnittstelle, für den Einstieg.
 

guni

Bekanntes Mitglied
Vielleicht gibt es eine Möglichkeit, dass du den doofen instanceOf operator
ich sehe da eigentlich keine Möglichkeit. Schließlich muss ich meiner Funktion irgendwie sagen, dass sie bei einer Datei (Link) nicht mehr "weitergraben" darf ...
wenn ich die die Struktur dann mal im Echtsystem anleg (zum Glück hab ich jetzt ein Visitor-Pattern, da muss ich das Ganze nur mehr um einen konkreten Visitor erweitern :lol:)
Du kannst doch in einer Schleife die Parents abfragen
klingt nicht allzu kompliziert ... das würd ich vielleicht sogar rekursiv schaffen
Code:
public String[] fullpath(Node node){
	Node current;
	if ((current = node.getParent) != null)
		fullpath(current);
}
vom Ansatz her dann noch ein Array.push oder sowas rein und das Ganze dann mit einer Funktion wrappen, die am Schluss ein
Array.reverse und ein Array.impolde("/")
aufruft, oder? Geht das In Java? Wie könnte ich das in meine Rekursion einbauen?
zwar nciht performant, aber ne bessere Schnittstelle, für den Einstieg
blenden wir mal eine Sekunde aus, dass ich ein kompletter Anfänger bin und tun so, als würde ich schon ewig Java können ;) ... was wäre dann sie eleganteste Lösung?

lg, guni
 
M

maki

Gast
ich sehe da eigentlich keine Möglichkeit. Schließlich muss ich meiner Funktion irgendwie sagen, dass sie bei einer Datei (Link) nicht mehr "weitergraben" darf ...
Ich meine mich dunkel errinnern zu können, das es eine Möglichekit gibt, ob die hier funktioniert müsste man mal testen, das wäre ungefähr so:
Dein Visitor hat zwei Methoden, eine visit(Folder folder), und eine visit(File file).
Das gab es noch einen Haken glaube ich...
Ob und wie das geht müsste ich nochmals nachlesen, verschieben wir das auf später, und leben wir für einen Moment mit dem "hässlichen" instanceof operator.

blenden wir mal eine Sekunde aus, dass ich ein kompletter Anfänger bin und tun so, als würde ich schon ewig Java können icon_wink.gif ... was wäre dann sie eleganteste Lösung?
Deine Lösung ist schon elegant.
Performanter aber etwas unflexibler wäre es, den Pfad nur bei der Erstellung zu berechnen.
Ich würde diene Lösung bevorzugen ;)
 

guni

Bekanntes Mitglied
also geht das mit dem array.push / array.implode in java ?!
aber wie merke ich mir, was schon im String[] drinsteht?
wie muss ich da mein return statement aufbaun???

lg, guni
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
I Composite Pattern für Ausgabe von Ausdruck Allgemeine Java-Themen 3
F Composite Pattern in Java? Allgemeine Java-Themen 1
J Meinung zum verwendeten Design Pattern Allgemeine Java-Themen 4
S Noch eine Design-Frage zu Setter Allgemeine Java-Themen 6
S ArrayList Design Allgemeine Java-Themen 4
S Interface Design von HookUp oder Callback Methoden für eigenes Framework Allgemeine Java-Themen 9
Kirby.exe Framework für Game Design Allgemeine Java-Themen 8
C WindowBuilder Design funktioniert nicht Allgemeine Java-Themen 0
M Diverse Design-Fragen Allgemeine Java-Themen 6
rentasad Design-Frage - Interfaces, Klassen, statische Methoden Allgemeine Java-Themen 3
M OOP Design Pattern - "extends Observable implements Observer" Allgemeine Java-Themen 0
T OOP Fehler im Design Allgemeine Java-Themen 9
perlenfischer1984 Welches Design Pattern ist geegneit. Allgemeine Java-Themen 7
perlenfischer1984 Hilfe bei Design (Pattern) Allgemeine Java-Themen 5
N Vererbung Design-Problem mit vorhandenen, von der Klasse unabhängigen Methoden Allgemeine Java-Themen 12
R Parameter Adapter - Design Allgemeine Java-Themen 1
D Bezüglich Design meines Codes Allgemeine Java-Themen 1
D OOP Design Pattern für GUI - Datenbank Anwendung Allgemeine Java-Themen 1
S Java Design Frage Allgemeine Java-Themen 10
L OOP Klassen-Design (static oder nicht?) Allgemeine Java-Themen 3
P Auf die Anzahl der Joins achten beim WS design Allgemeine Java-Themen 1
M OOP Design Frage Allgemeine Java-Themen 2
J Domain Driven Design - Modellierungsfrage Allgemeine Java-Themen 3
F Welches Design Pattern? Allgemeine Java-Themen 3
H MVC Design Allgemeine Java-Themen 9
J Swing Eigenes Button-design Allgemeine Java-Themen 2
Q Kapselung Allgemeine Design- Frage Allgemeine Java-Themen 8
Z Design um boolsche ausdrücke zu speichern & auszuwerten Allgemeine Java-Themen 3
A Sinnvolles Software Design bei Eigenschaftsänderungen von Objekten Allgemeine Java-Themen 7
C Gutes Code Design (3 Schichten Modell) Allgemeine Java-Themen 19
D Design Stations-Gitter Allgemeine Java-Themen 4
M Public Static importRunning -> Bad Design oder ok ? Allgemeine Java-Themen 5
L Software-Design: Kommunikation mit SerialPort (RXTX) Allgemeine Java-Themen 2
D [Drag&Drop] Design-Pattern-Frage Allgemeine Java-Themen 4
G Design Patterns für Programm Allgemeine Java-Themen 3
I Wie populär ist Design by Contract in Java und was haltet ihr davon? Allgemeine Java-Themen 5
Landei Design-Problem Formel-Parser Allgemeine Java-Themen 10
J Aktionen im State-Design-Modell Allgemeine Java-Themen 3
S Design Oberfläche Allgemeine Java-Themen 2
L Design-Frage: Platzierung der Save-Methode Allgemeine Java-Themen 3
G Domain Driven Design Model Allgemeine Java-Themen 14
G konkretes Domain Driven Design Aggregate Allgemeine Java-Themen 2
ruutaiokwu welches design pattern? frage an die oo-experten unter euch... Allgemeine Java-Themen 3
G Accordion Design Pattern Frage Allgemeine Java-Themen 2
hdi Hilfe beim Design (Stichwort OO, Pattern, ...) Allgemeine Java-Themen 11
B Design Problem Allgemeine Java-Themen 8
faulelotte Verständnisproblem Domain Driven Design Allgemeine Java-Themen 3
S Frage zum Design der Datenstruktur Allgemeine Java-Themen 10
D design gesucht - Angabe von zu ersetzenden substrings Allgemeine Java-Themen 2
D Design ohne Getter und Setter Allgemeine Java-Themen 8
D Design: on-the-fly-Parsing + Datenstrukturen Allgemeine Java-Themen 5
N Welches design pattern? Allgemeine Java-Themen 8
D design client server Allgemeine Java-Themen 10
T Design-Frage Allgemeine Java-Themen 14
S XML-Parsing / public-Member-Variablen / Design-Frage Allgemeine Java-Themen 8
S JToolBar Design Allgemeine Java-Themen 3
M Bildersyncronisierung - Design Patterns? Allgemeine Java-Themen 2
T Design - Exception in Thread Allgemeine Java-Themen 3
N Design-Frage: persistent machen per Reflection Allgemeine Java-Themen 3
M Frage zum Design :: allgemein Allgemeine Java-Themen 6
M MVC Design Pattern - Verständniss Fragen Allgemeine Java-Themen 3
U Frage zu DB Design Allgemeine Java-Themen 3
K Design / Implementierung Allgemeine Java-Themen 5
N Checkstyle - Design for Extension Allgemeine Java-Themen 4
F Design Pattern zur Realisierung von Mehrfachvererbung? Allgemeine Java-Themen 8
E Was ist ein gutes Design fuer meine Programm? Allgemeine Java-Themen 3
F Paket und Software Design Fragen. Allgemeine Java-Themen 5
P Apple Design Allgemeine Java-Themen 5
S design frage Allgemeine Java-Themen 10
T Design-Tipp gesucht Allgemeine Java-Themen 2
M Design von Java Klassen Allgemeine Java-Themen 2
G java design von klassen und projekten Allgemeine Java-Themen 6
K Design: Klassen in Pakete aufteilen - Eure Meinung Allgemeine Java-Themen 8
S Programmierstil / design Allgemeine Java-Themen 9
S Exception design Allgemeine Java-Themen 2
m@nu Exception-Design Allgemeine Java-Themen 4
R Design-Frage Allgemeine Java-Themen 9
N Hilfe beim Design Allgemeine Java-Themen 13
D Design Pattern: Singleton Allgemeine Java-Themen 4
Torres Design-Problem mit Jakarta Struts Allgemeine Java-Themen 2
A Anwendungs-Design (Plugin-Architektur) Allgemeine Java-Themen 4
mihe7 equals und instanceOf pattern matching Allgemeine Java-Themen 9
L Pattern Eventhandler Allgemeine Java-Themen 5
EinNickname9 Best Practice Singleton und Singleton mit Instanz zu anderer Klasse -Pattern Allgemeine Java-Themen 30
Z MVC Pattern - sinnvolle Integration Allgemeine Java-Themen 6
Kirby.exe Filename nach bestimmtem Pattern durchsuchen Allgemeine Java-Themen 5
Meeresgott Best Practice "Spezifisches" Factory Pattern ? Allgemeine Java-Themen 1
H Strategy Pattern - changeColor() Methode - input rgd oder hex einlesen Allgemeine Java-Themen 1
M Vaadin MVP Pattern Allgemeine Java-Themen 1
N Java MVC Pattern richtig anwenden Allgemeine Java-Themen 24
K Factory Pattern: Mit Generics umgehen Allgemeine Java-Themen 6
J Compilerfehler bis in java.util.regex.Pattern... Allgemeine Java-Themen 2
B MVC-Pattern größeres Beispiel Allgemeine Java-Themen 16
GreenTeaYT Verstehe nicht ganz das Observer Pattern in einer Arrayliste? Allgemeine Java-Themen 3
L Erste Schritte Java Date Format Pattern bestimmten Allgemeine Java-Themen 2
D Pattern mit Pattern vergleichen Allgemeine Java-Themen 3
S Hilfe bei geeignetem Pattern (Decorierer) Allgemeine Java-Themen 2
J Pattern aus String entfernen Allgemeine Java-Themen 2
S Pattern.Match Suche: For Schleife einbinden und in Liste schreiben Allgemeine Java-Themen 3
D Variablen zur Laufzeit global speichern (Registry Pattern?) Allgemeine Java-Themen 6

Ähnliche Java Themen

Neue Themen


Oben