Hängt natürlich davon ab, was Ihre Designziele sind. Wenn Ihr Ziel ist, dass der Baum/Graph zu irgendeinem Zeitpunkt modifizierbar sein sollte, dann kann ein Blatt tatsächlich ein Elternknoten werden. In diesem Fall ist es in Ordnung, hierarchierelevante Methoden in der Komponente zu definieren.
Ein anderer Ansatz (obwohl ich weiß nicht, ob dies auf Ihren Anwendungsfall anwendbar ist) ist folgende zwei Ideen zu nutzen:
- die Struktur unveränderlich
von Funktion Separate Struktur
- Machen
Indem wir die Struktur unveränderlich machen, können wir alle Graphenkonstruktionen auf die Konstruktoren schieben. Damit umgehen wir die von Ihnen erwähnte Typ-Casting-Problematik und machen das Ganze leichter verständlich.
Durch die Trennung der Struktur von der Funktion müssen wir die Strukturinformationen überhaupt nicht an Kunden veröffentlichen, stattdessen bieten wir die Funktionalität, die wir anbieten möchten. Damit können wir Liskov, Demeter und die anderen OO-Sachen behalten.
Dies ist, wie es aussehen kann wie:
public interface Node {
// Here we offer the "functionality", but we don't
// publish the "structure". This is made-up, I
// don't know your use-case.
void process(Consumer<Payload> payloadConsumer);
}
public class Leaf implements Node {
private Payload payload;
public Lead(Payload payload) {
this.payload = payload;
}
@Override
public void process(Consumer<Payload> payloadConsumer) {
payloadConsumer.accept(payload);
}
}
public class ParentNode implements Node {
private List<Node> children;
public ParentNode(Node... children) {
this.children = asList(children);
}
// Here we implement the processing recursively.
// All children can respond according to their semantics,
// instead of assuming any structure beyond what we know.
@Override
public void process(Consumer<Payload> payloadConsumer) {
children.forEach(child -> child.process(payloadConsumer));
}
}
Natürlich können Sie Ihre eigene Node
Arten je nachdem, welche Art von Logik definieren können Sie darstellen möchten. Sie können mehrere Operationen definieren, nicht nur die eine process()
Methode, die ich gemacht habe. Dann können Sie alles so zusammenstecken:
# 2. Sie können nichts zu/von einem Blatt hinzufügen oder entfernen - verschieben Sie den Code in Composite. – dbugger
@croxis, ja 2. Option ist auch ein Weg, und ich werde meine Frage bearbeiten, um das auch zu integrieren. Aber es hat auch ein Problem, es wird die Component-Schnittstelle sein, die ausgesetzt wird, und um die Operation add, remove aufzurufen, wird eine explizite Typumwandlung benötigt und wiederum gegen gute Designprinzipien. –
@ nits.kk Warum ist explizites Typecasting erforderlich? Das ist nicht für das Muster erforderlich (möglicherweise für Ihr Design, wenn Sie Ihre Frage mit mehr Details aktualisieren). Trotzdem werden Sie oft feststellen, dass gute Designprinzipien miteinander in Konflikt geraten können. Nicht jedes Problem hat eine saubere Lösung, manchmal wählen Sie das unordentlichste. – cyroxis