2009-04-05 22 views
1

Eine Frage über Zusammensetzung und Objektorientierung:Java Zusammensetzung Frage

Ich versuche, mehr Funktionen für eine Klasse (Java TreeMap als ein Beispiel) zu implementieren.

public class TreeMap<K,V> 
    extends AbstractMap<K,V> 
    implements NavigableMap<K,V>, Cloneable, Serializable 

Mit Zusammensetzung ist die way to go on this, also würde ich zuerst eine wiederverwendbar Weiterleitungsklasse schaffen haben, die die Funktionalität der Klasse wickeln wird, während zugleich es nur, dass auszukommen, so dass es in Zukunft anderswo verwendet werden.

public class ForwardingNavigableMap<K,V> implements NavigableMap<K,V> 
{ 
... 
} 

Ich würde dann mit dem Erstellen einer Wrapper-Klasse gehen, die die neu erstellte reusable forwarding class, wie so erbt:

public class BetterTreeMap<K,V> extends ForwardingNavigableMap<K,V> 
{ 
/* some new cool features here */ 
} 

Was die ich in brauchen passiert, wenn TreeMap eine Reihe von feinen Features enthält meine Klasse, die nicht Teil der NavigableMap-Schnittstelle sein könnte? Sollte ich dann weitermachen, indem ich mein eigenes Interface für TreeMap deklariere und das in meiner wiederverwendbaren Klasse implementiere? Jede Eingabe hier ist willkommen.

Antwort

1

Der einfachste Ansatz ist, einfach die bestehende Klasse Sie komplizierte Dinge mehr machen nicht

public class MyTreeMap<K,V> extends TreeMap<K,V> { 
    // add your overridden or extra methods here. 
} 

Ich schlage vor, zu verlängern, als sie sein müssen.

Wenn dies nicht geeignet ist, könnten Sie vielleicht erklären, was Sie erreichen möchten.

+0

Ich versuche, eine Objektbegrenzungshierarchie für die Kollisionserkennung in einem einfachen Spiel zu erstellen. Ich bin nicht sicher, ob TreeMap das ist, was ich will, also muss ich es später ersetzen können, weshalb die Präferenz von Komposition über Vererbung (erweitert) – Andreas

+0

Composition erlaubt dynamische Änderung des Typs der zugrunde liegenden Map. Vererbung erfordert eine Neukompilierung, um sie zu ändern. Wie schwer wird es sein, den Code neu zu kompilieren, wenn Sie das möchten? –

1

Wenn diese coolen neuen Funktionen auf anderen Datenstrukturen implementiert werden, die Sie verwenden werden, absolut.

Wenn nicht, versuchen Sie, Ihre Klassen mit nutzlosen Schnittstellen zu überlasten. Halten Sie das Durcheinander auf ein Minimum.

1

Das Problem hier ist, dass in diesem Beispiel TreeMap wie eine Schnittstelle fungiert. Sie können es als solches behandeln, indem Sie alle Methoden für die Weiterleitung überschreiben. Es ist nicht so, als wäre ein Zustand in einem leeren . Dies ist jedoch ein fragiler Ansatz, da neue Methoden (oder solche, die Sie verpasst haben) nicht behandelt werden.

Vielleicht muss Ihre Klasse keine Map sein. Sie könnten eine für Ihren Code geeignete Schnittstelle erstellen, aber eine asMap/10/asNavigableMap für die Verwendung mit Bibliotheken und nicht spezifischem Code.

1

Was passiert, wenn TreeMap eine Reihe von feinen Features enthält, die ich in meiner Klasse benötige, die nicht Teil der NavigableMap-Schnittstelle sein könnten?

Dies ist das Problem bei der Verwendung der Zusammensetzung in Fällen wie diesem. Wenn Sie feststellen, dass Sie eine Reihe von Wrapper-Methoden erstellen, die nur dieselben Methoden auf TreeMap aufrufen, ist dies ein Argument für die Vererbung. Also, wenn Sie eine erhebliche Anzahl von Methoden, die

aussehen
public Set<K> keySet() 
{ 
    return myTreeMap.keySet(); 
} 

Sie nur TreeSet erweitern möchten alle ihre Methoden kostenlos zu bekommen, dann überschreiben die, die Sie ändern möchten.

Wenn die Klasse, die Sie entwerfen eine TreeMap intern verwendet, und Client-Programme müssen nicht darüber wissen, dann sollten Sie Komposition verwenden. Wenn Ihre Klasse eine TreeMap mit einigen hinzugefügten oder geänderten Features ist, verwenden Sie die Vererbung.

2

Angenommen, Sie beabsichtigen nicht, dies zu einer pulic-API zu machen (was bedeutet, dass Sie es nicht an Drittanbieter versenden und erwarten, dass sie es nutzen), können Sie Folgendes tun.

Vorausgesetzt, dass Sie (möglicherweise) Zugriff auf TreeMap-spezifische Methoden benötigen, aber möglicherweise später auch die Vererbung auf etwas anderes als TreeMap ändern, solange Sie keinen Code schreiben, der davon abhängt, dass die Klasse eine TreeMap ist (Bsp. beziehen Sie sich niemals auf TreeMap neben der "extends TreeMap"), dann sind Sie sicher mit extends. Dazu müssten Sie eine Schnittstelle schreiben, die die TreeMap-Methoden bereitstellt.

Wenn Sie feststellen, dass Sie TreeMap nicht verklagen und später etwas anderes verwenden möchten, da Sie nicht auf TreeMap verweisen, ist das kein Problem. Sie bleiben dann mit allen Aufrufen von TreeMap-spezifischen Methoden ... wenn all diese zur selben Zeit weggehen, zu der Sie nicht länger von TreeMap ausgehen, dann können Sie loslegen. Wenn dies nicht der Fall ist, müssen Sie Ihre eigene Implementierung der Methoden schreiben, die Sie benötigen.

Um herauszufinden, was Sie brauchen oder nicht, wenn Sie von TreeMap geändert haben, würden Sie alle Methoden auskommentieren, die Sie in die Schnittstelle setzen, wenn der Code mit der leeren Schnittstelle kompiliert, die Sie gut gehen, wenn nicht Sie müssen die fehlenden Methoden wieder in die Schnittstelle einfügen. Wenn die Klasse, für die Sie sich entschieden haben, zu erweitern, nicht die fehlenden Methoden zur Verfügung stellt, mit denen Sie zu tun haben (oder Sie von TreeMap aus erweitern mussten).

Die alternative Lösung ist, im Voraus herauszufinden, ob Sie wirklich TreeMap benötigen. Ich bin mir nicht sicher, ob ich zu weit in ein Projekt gehen möchte, bei dem ich nicht genau wusste, was ich für meine Datenstrukturen brauche.

1

Setzen Sie alle Ihre eigenen neuen Methoden in eine neue Schnittstelle und erstellen Sie eine Klasse, die diese Schnittstelle ebenfalls implementiert.

Hier wäre es

public class MyMap implements MyInterface, NavigableMap { 
... 
} 

Sie könnten dann diese Klasse lassen die Klasse erweitern Sie wollen, aber ich würde es besser betrachten ein eigenes Mitglied MyMap ist der Klasse TreeMap haben, wie Sie dann nur diejenigen entlarven Methoden, die Sie wirklich wollen und nicht alle, die TreeMap zusätzlich hat.

Es erfordert viel Arbeit, die Weiterleitungsmethoden zu schreiben, aber z.B. Eclipse verfügt über gute Refactorings, mit denen Sie diese automatisch generieren können.