Ist es OK, um einen "leeren" Klasse, die eine andere Klasse erweitert?
Sagen wir, ich habe eine Klasse Foo
dass eine Reihe von Logik und eine andere Klasse Bar
die im wesentlichen die gleichen. Jedoch, wie Foo
und Bar
sind unterschiedliche (aber Verwandte) Personen brauche ich die Differenz ersichtlich sein aus meinem code (d.h. ich kann Ihnen sagen, ob eine Instanz ist eine Foo
oder eine Bar
)
Als ich war whacking diese zusammen, ohne viel dachte, ich landete mit der folgenden:
public class Foo {
/* constructors, fields, method, logic and what-not */
}
public class Bar extends Foo {
/* nothing here but constructors */
}
Ist das OK? Ist es besser zu machen Bar
eine composite-Klasse? e.g:
public class Bar {
private Foo foo;
/* constructors and a bunch of wrapper methods that call
into foo */
}
Oder auch, wenn wir schon dabei sind, etwas mehr low-tech:
public class Foo {
/* constructors, fields, method, logic and what-not */
private boolean isABar; //Could be an enum
}
Was denkst du? Wie gehst du mit diesen "marker-Klassen'?
Als ein Beispiel, wie mein code Mai Wunsch zu behandeln Foo
und Bar
anders, mein code müsste in der Lage sein, um Dinge zu tun wie List<Foo>
und List<Bar>
. Ein Foo
konnte nicht gehen, in eine List<Bar>
- und Umgekehrt.
- Gut, dann, meine Lösung der AbstractFoo ist perfekt! Sie müssen nur eine Liste mit<AbstractFoo>, und Sie können sowohl " Foo " und " Bar zu.
- "Ein Foo konnte nicht gehen, in eine Liste<Bar> und Umgekehrt." - aber du bist der Punkt steht immer noch da Foo und Bar sind eigene Implementierungen
- Können Sie bitte erläutern, was das bedeutet: sagen wir, ich habe eine Klasse Foo, die eine Reihe von Logik und anderen Klasse-Bar, die im wesentlichen die gleichen << das ist doch das gleiche oder nicht?
- John: mein code neesd in der Lage sein, den Unterschied zu kennen. Als ein erfundenes Beispiel, wenn ich ein 'GoodInteger' und ein 'BadInteger'; Sie hätte den gleichen code, definiert Sie aber meinen code wissen muss, um die guten von den schlechten.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Meiner Meinung nach, ist es am besten, wenn
Foo
undBar
Unterklasse aus einer gemeinsamen Vorfahren-Klasse (vielleichtAbstractFoo
), die hat alle Funktionen, die. Was ist der Unterschied im Verhalten besteht zwischenFoo
undBar
? Code, der Unterschied zu einer abstrakten Methode inAbstractFoo
werden, nicht mit einemif
- Anweisung in Ihrem code.Beispiel: Anstatt:
Tun Sie dies:
Der Vorteil dieses Ansatzes ist, dass wenn Sie eine Dritte Klasse, das ist ähnlich wie
Foo
hat aber nur ein wenig von der Unterschied, die Sie nicht haben, um durch alle gehen Sie den code und fügen Sie Bearbeiten alleif
Aussagen. 🙂Es hängt alles von der Bedeutung des " Foo " und " Bar-Klassen. Was Sie vertreten, und was ist Ihr Zweck. Bitte klären Sie.
Kann ich mir vorstellen, Situationen, wenn jede Ihrer Lösungen und die vorgeschlagenen Lösungen die richtige ist.
Foo und Bar Erben von FooBarImplementation
Ich würde ein Klasse FooBarImplementation Umsetzung des gemeinsamen Funktionen Foo und Bar. Foo und Bar daraus. Aber in deinem code nie immer verwenden Sie den Typ FooBarImplementation. Meine Java-Tage sind etwas hinter mir, aber ich denke, es muss eine Art und Weise zu verstecken FooBarImplementation aus dem Benutzer-code (so dass es geschützt ist, oder das Paket nur sichtbar, je nach Projekt-Organisation. Auf diese Weise werden keine Benutzer-code mix Foo für eine Bar (und Umgekehrt)?
Foo und Bar aus FooBarImplementation
Andere Möglichkeit wäre, um " Foo " und " Bar vorne jede Ihrer Methoden, um eine interne Klasse (wieder FooBarImplementation). Auf diese Weise gibt es keine Möglichkeit, den Benutzer code kann Foo und Bar.
NICHT machen, Foo erbt von Bar (oder Umgekehrt)
Sollte Foo erbt von Scheune, Foo wäre eine Bar, soweit es die Sprache betrifft. Tun Sie es nicht, verlieren Sie den Unterschied zwischen den Objekten, und dies ist, was Sie nicht wollen.
Nicht boolean verwenden, und whataver-Typ-Feld
Dies ist die schlechteste Idee, Sie könnte kommen über. Bjarne Stroustrup gewarnt gegen diese Art von antipattern für C++, und C++ ist noch nicht alles über die OOP. Also ich denke, dieses Muster ist noch mehr "anti" für Java... 🙂
Wenn es irgendeine Wahrscheinlichkeit, dass
Foo
undBar
könnte eines Tages auseinander in der Umsetzung, dann ist deine Frage beantwortet - verwenden Sie Vererbung, in welcher Weise auch immer am besten scheint.Aber wenn Sie sich absolut sicher sind, dass Sie nie auseinander gehen, dann ist klar, Sie suchen nach etwas, das dargestellt werden soll, durch eine einzige Klasse, wie
ThingThatIsEitherFooOrBar
.Und mit dieser Klasse gemacht, statt ihm eine boolean-Eigenschaft, wie
isFoo
wäre, wäre es viel besser nehmen Sie einen Blick auf, warum Sie benötigen, um zu unterscheiden, Foo von Bar. Was ist es über Foos macht, die Sie behandeln Sie anders als Bars? Das herauszufinden, und stellen Sie einer Eigenschaft, die angibt, die Informationen, die unterscheidet sich. Sind Foos größer? Dann machen Sie eine Eigenschaft für die Größe (selbst wenn es ein enum mit den Werten "Foo-sized" und "Bar" Größe).Das ist ungefähr so viel, wie man sagen kann, ohne spezifische Beispiele von dem, was Foo und Bar werden könnte.
Grundsätzlich müssen Sie den Strategie-Muster.
Jeden Fall verwenden Sie eine Boolesche Eigenschaft. Es ist die einfachste Lösung, es sei denn, Sie sehen die Bar Klasse brauchen, es zu ändern die Schnittstelle später (z.B. überschreiben seiner Methoden).
Vererbung am besten ist.
Eine Boolesche Eigenschaft, die Klasse muss wissen über die Existenz von zwei verschiedenen Arten von Objekten, und das ist nicht leicht erweiterbar auf mehr als zwei. Darüber hinaus ist dieser Ansatz lässt Sie nicht überladen Funktionen.
Die Zusammensetzung macht Sie zu schreiben, Wrapper für alle Funktionen.
Ihre Daten war nicht klar genug, aber basierend auf dem, was ich glaube, Sie brauchen, ich bin verwirrt, warum Sie nicht einfach gehen mit einer 4. option:
Kein entweder Typ a und B Erben von MainStuff, oder machen MainStuff ein Datenelement von Typ a und TypeB. Dies hängt von der Bedeutung dessen, was diese 3 Klassen sind.
Wie andere gesagt haben, es hängt, aber wenn Sie gemeinsame Funktionalität zwischen Foo und Bar und der Unterschied in der Funktionalität ausgedrückt werden kann, als Parameter, dann vote ich für Unterklassen.
Dies war im Grunde, was wir tun, am Ende eine praktische software, natürlich.
Sollten wir implementieren ein sudoku-Spiel, und am Ende hatten wir eine "AbstractPlayfield", die in der Lage war, um eine beliebige Menge von Regeln zu einem beliebigen Spielfeld. Diese AbstractPlayfield war Unterklassen durch die einzelnen Varianten sollten wir umsetzen. Diese Unterklassen Parameter (meist die Regeln und die Form der platine) für die abstrakte Spielfläche und alles funktionierte wie ein Charme. Landeten wir sogar mit mehr Vererbung in diesen Unterklassen, da mehrere Varianten enthalten die Regeln "Nummern müssen eindeutig sein, in einer Reihe" und "Nummer muss eindeutig sein in einer Spalte".
Mit diesem waren wir in der Lage, die Arbeit zu beenden, die geschätzt wurde, für über 2 Monate vor über 3 Tage 🙂 (Und Sie ärgern uns mit "Test-diese kleinen Attribut-Einstellung Klassen, weil Sie vielleicht bugs drin! Testen Sie Sie! Testen Sie Sie! Wir dont care, dass alle wichtigen Logik wird getestet!".)
Auf der anderen Seite, wenn die Klasse Bar hat keine Besondere andere Funktionen von der Bar, ich sehe nicht den Punkt, indem es - zumindest aus den Daten, die Sie mir geben. Es könnte Sinn machen, wenn Sie das tun wollten einige Operationen auf der Grundlage von Arten-und Versand-on-Typ, aber ich kann nicht Lesen, dass von Foo und Bar. In diesem Fall würde ich nicht schaffen, Bar, aufgrund von YAGNI.
Wenn es keinen Unterschied im Verhalten zwischen Foo und Bar, dann der name der Klasse "Foo" ist nicht Abstrakt genug. Identifizieren Sie die gemeinsamen Abstraktion zwischen Foo und Bar, und benennen Sie die Klasse entsprechend. Geben Sie dann ein Mitglied Feld in der Klasse zu identifizieren Instanzen wie "Foo", "Bar", etc. Verwenden Sie eine enum-wenn Sie möchten, zu beschränken, möglich Werte "Foo" und "Bar".