Gibt es einen Grund, Klassen für "normale alte Daten" zu verwenden?


43

In altem Code sehe ich gelegentlich Klassen, die nichts als Wrapper für Daten sind. so etwas wie:

class Bottle {
   int height;
   int diameter;
   Cap capType;

   getters/setters, maybe a constructor
}

Mein Verständnis von OO ist, dass Klassen Strukturen für Daten und die Methoden zur Verarbeitung dieser Daten sind. Dies scheint Objekte dieses Typs auszuschließen. Für mich sind sie nichts anderes als eine structsArt Niederlage des Zwecks von OO. Ich denke nicht, dass es notwendigerweise böse ist, obwohl es ein Codegeruch sein kann.

Gibt es einen Fall, in dem solche Objekte notwendig wären? Wenn dies häufig verwendet wird, lässt es das Design vermuten?


1
Dies beantwortet Ihre Frage nicht ganz, scheint aber dennoch relevant zu sein: stackoverflow.com/questions/36701/struct-like-objects-in-java
Adam Lear

2
Ich denke, der Begriff, den Sie suchen, ist POD (Plain Old Data).
Gaurav

9
Dies ist ein typisches Beispiel für strukturierte Programmierung. Nicht unbedingt schlecht, nur nicht objektorientiert.
Konrad Rudolph

1
Sollte dies nicht auf Stapelüberlauf sein?
Muad'Dib,

7
@ Muad'Dib: technisch, es ist über Programmierer. Ihrem Compiler ist es egal, ob Sie einfache alte Datenstrukturen verwenden. Ihre CPU genießt es wahrscheinlich (in der Art "Ich liebe den Geruch von Daten frisch aus dem Cache"). Es sind die Leute, die sich aufhängen: "Macht das meine Methode weniger rein?" Fragen.
Shog9

Antworten:


67

Auf keinen Fall böse und kein Codegeruch in meinem Kopf. Datencontainer sind gültige OO-Bürger. Manchmal möchten Sie zusammengehörige Informationen zusammenfassen. Es ist viel besser, eine Methode wie diese zu haben

public void DoStuffWithBottle(Bottle b)
{
    // do something that doesn't modify Bottle, so the method doesn't belong
    // on that class
}

als

public void DoStuffWithBottle(int bottleHeight, int bottleDiameter, Cap capType)
{
}

Mit einer Klasse können Sie auch einen zusätzlichen Parameter zu Bottle hinzufügen, ohne jeden Aufrufer von DoStuffWithBottle zu ändern. Außerdem können Sie Bottle in Unterklassen unterteilen und die Lesbarkeit und Organisation Ihres Codes bei Bedarf weiter verbessern.

Es gibt auch einfache Datenobjekte, die beispielsweise als Ergebnis einer Datenbankabfrage zurückgegeben werden können. Ich glaube, dass der Begriff für sie in diesem Fall "Datenübertragungsobjekt" ist.

In einigen Sprachen gibt es auch andere Überlegungen. Beispielsweise verhalten sich in C # Klassen und Strukturen unterschiedlich, da Strukturen ein Werttyp und Klassen Referenztypen sind.


25
Nein. DoStuffWithsollte ein Verfahren von der BottleKlasse in OOP (und soll vermutlich unveränderlich sein, auch). Was Sie oben geschrieben haben, ist kein gutes Muster in einer OO-Sprache (es sei denn, Sie arbeiten mit einer älteren API zusammen). Es ist jedoch ein gültiger Entwurf in einer Nicht-OO-Umgebung.
Konrad Rudolph

11
@Javier: Dann ist Java auch nicht die beste Antwort. Javas Betonung auf OO ist überwältigend, die Sprache kann eigentlich nichts anderes.
Konrad Rudolph

11
@JohnL: Ich habe natürlich vereinfacht. Im Allgemeinen kapseln Objekte in OO jedoch den Status und keine Daten. Dies ist eine feine, aber wichtige Unterscheidung. Der Punkt von OOP ist genau, nicht viele Daten herumzusitzen. Es werden Nachrichten zwischen Status gesendet , die einen neuen Status erstellen. Ich verstehe nicht, wie Sie Nachrichten an oder von einem methodenlosen Objekt senden können. (Und dies ist die ursprüngliche Definition von OOP, damit ich sie nicht als fehlerhaft betrachte.)
Konrad Rudolph

13
@Konrad Rudolph: Deshalb habe ich den Kommentar innerhalb der Methode explizit gemacht. Ich bin damit einverstanden, dass Methoden, die Instanzen von Bottle betreffen, in diese Klasse fallen sollten. Wenn jedoch ein anderes Objekt seinen Status basierend auf den Informationen in Bottle ändern muss, ist mein Design meiner Meinung nach ziemlich gültig.
Adam Lear

10
@Konrad, ich bin nicht einverstanden, dass doStuffWithBottle in die Flaschenklasse gehört. Warum sollte eine Flasche wissen, wie man Sachen mit sich selbst macht? doStuffWithBottle gibt an, dass etwas anderes mit einer Flasche etwas zu tun hat. Wenn die Flasche das hätte, wäre das eine enge Verbindung. Wenn die Bottle-Klasse jedoch eine isFull () -Methode hätte, wäre das völlig angemessen.
Nemi

25

In einigen Fällen sind Datenklassen gültig. DTOs sind ein gutes Beispiel, das von Anna Lear erwähnt wird. Im Allgemeinen sollten Sie sie jedoch als den Keim einer Klasse betrachten, deren Methoden noch nicht entstanden sind. Und wenn Sie in altem Code auf viele davon stoßen, behandeln Sie sie als starken Codegeruch. Sie werden häufig von alten C / C ++ - Programmierern verwendet, die noch nie auf die OO-Programmierung umgestiegen sind und ein Zeichen für die prozedurale Programmierung sind. Wenn Sie sich die ganze Zeit auf Getter und Setter verlassen (oder, noch schlimmer, auf den direkten Zugriff nicht privater Mitglieder), können Sie Probleme bekommen, bevor Sie es merken. Stellen Sie sich ein Beispiel für eine externe Methode vor, für die Informationen von benötigt werden Bottle.

Hier Bottleist eine Datenklasse:

void selectShippingContainer(Bottle bottle) {
    if (bottle.getDiameter() > MAX_DIMENSION || bottle.getHeight() > MAX_DIMENSION ||
            bottle.getCapType() == Cap.FANCY_CAP ) {
        shippingContainer = WOODEN_CRATE;
    } else {
        shippingContainer = CARDBOARD_BOX;
    }
}

Hier haben wir Bottleetwas Verhalten gegeben):

void selectShippingContainer(Bottle bottle) {
    if (bottle.isBiggerThan(MAX_DIMENSION) || bottle.isFragile()) {
        shippingContainer = WOODEN_CRATE;
    } else {
        shippingContainer = CARDBOARD_BOX;
    }
}

Das erste Verfahren gegen die Tells-nicht-Frage Prinzip, und indem sie Bottlestumm wir haben implizites Wissen über Flaschen lassen, wie zum Beispiel , was macht einen Fragle (die Cap), Schlicker in einer Logik , die außerhalb dem ist BottleKlasse. Sie müssen auf der Hut sein, um diese Art von "Leckage" zu verhindern, wenn Sie sich gewöhnlich auf Getter verlassen.

Die zweite Methode fragt Bottlenur nach dem, was sie für ihre Arbeit benötigt, und Bottleentscheidet, ob sie zerbrechlich oder größer als eine bestimmte Größe ist. Das Ergebnis ist eine viel lockere Kopplung zwischen der Methode und der Implementierung von Bottle. Ein angenehmer Nebeneffekt ist, dass die Methode sauberer und ausdrucksvoller ist.

Sie werden selten von so vielen Feldern eines Objekts Gebrauch machen, ohne eine Logik zu schreiben, die sich in der Klasse mit diesen Feldern befinden sollte. Finde heraus, was diese Logik ist und verschiebe sie dahin, wo sie hingehört.


1
Ich kann nicht glauben, dass diese Antwort keine Stimmen hat (nun, Sie haben jetzt eine). Dies mag ein einfaches Beispiel sein, aber wenn OO genug missbraucht wird, erhalten Sie Serviceklassen, die sich in Albträume verwandeln, die Tonnen von Funktionen enthalten, die in Klassen eingekapselt sein sollten.
Alb

"Von alten C / C ++ - Programmierern, die noch nie den Übergang (sic) zu OO gemacht haben"? C ++ Programmierer sind in der Regel ziemlich OO, da es eine OO - Sprache ist, dh der ganze Sinn von C ++ anstelle von C
nappyfalcon

7

Wenn Sie so etwas brauchen, ist das in Ordnung, aber bitte, bitte, bitte machen Sie es so

public class Bottle {
    public int height;
    public int diameter;
    public Cap capType;

    public Bottle(int height, int diameter, Cap capType) {
        this.height = height;
        this.diameter = diameter;
        this.capType = capType;
    }
}

anstelle von so etwas wie

public class Bottle {
    private int height;
    private int diameter;
    private Cap capType;

    public Bottle(int height, int diameter, Cap capType) {
        this.height = height;
        this.diameter = diameter;
        this.capType = capType;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public int getDiameter() {
        return diameter;
    }

    public void setDiameter(int diameter) {
        this.diameter = diameter;
    }

    public Cap getCapType() {
        return capType;
    }

    public void setCapType(Cap capType) {
        this.capType = capType;
    }
}

Bitte.


14
Das einzige Problem dabei ist, dass es keine Validierung gibt. Jede Logik, die angibt, was eine gültige Flasche ist, sollte in der Flaschenklasse enthalten sein. Mit Ihrer vorgeschlagenen Implementierung kann ich jedoch eine Flasche mit negativer Höhe und negativem Durchmesser verwenden. Es gibt keine Möglichkeit, Geschäftsregeln für das Objekt durchzusetzen, ohne sie bei jeder Verwendung des Objekts zu validieren. Mit der zweiten Methode kann ich sicherstellen, dass, wenn ich ein Bottle-Objekt habe, es gemäß meinem Vertrag ein gültiges Bottle-Objekt war, ist und immer sein wird.
Thomas Owens

6
Dies ist ein Bereich, in dem .NET einen leichten Vorteil gegenüber Eigenschaften hat, da Sie einen Eigenschafts-Accessor mit Validierungslogik hinzufügen können, der dieselbe Syntax aufweist, als ob Sie auf ein Feld zugreifen würden. Sie können auch eine Eigenschaft definieren, bei der Klassen den Eigenschaftswert abrufen können, ihn jedoch nicht festlegen.
JohnL

3
@ user9521 Wenn Sie sicher sind, dass Ihr Code keinen schwerwiegenden Fehler mit "schlechten" Werten verursacht, wählen Sie Ihre Methode. Wenn Sie jedoch eine weitere Validierung oder die Fähigkeit zum verzögerten Laden oder andere Überprüfungen beim Lesen oder Schreiben von Daten benötigen, verwenden Sie explizite Get- und Setter-Methoden. Persönlich neige ich dazu, meine Variablen privat zu halten und aus Gründen der Konsistenz Getter und Setter zu verwenden. Auf diese Weise werden alle meine Variablen unabhängig von der Validierung und / oder anderen "fortgeschrittenen" Techniken gleich behandelt.
Jonathan

2
Der Vorteil der Verwendung des Konstruktors besteht darin, dass es viel einfacher ist, die Klasse unveränderlich zu machen. Dies ist wichtig, wenn Sie Multithread-Code schreiben möchten.
Fortyrunner

7
Ich würde die Felder wann immer möglich endgültig machen. Meiner Meinung nach hätte ich es vorgezogen, dass Felder standardmäßig endgültig sind und ein Schlüsselwort für veränderbare Felder haben. zB var
Peter Lawrey

6

Wie @Anna sagte, definitiv nicht böse. Sicher können Sie Operationen (Methoden) in Klassen einfügen, aber nur, wenn Sie möchten . Sie müssen nicht haben zu.

Erlauben Sie mir einen kleinen Kritikpunkt über die Idee, dass Sie Operationen in Klassen einordnen müssen, zusammen mit der Idee, dass Klassen Abstraktionen sind. In der Praxis ermutigt dies Programmierer dazu

  1. Machen Sie mehr Klassen als nötig (redundante Datenstruktur). Wenn eine Datenstruktur mehr Komponenten als nur minimal erforderlich enthält, ist sie nicht normalisiert und enthält daher inkonsistente Zustände. Mit anderen Worten, wenn es geändert wird, muss es an mehr als einer Stelle geändert werden, um konsistent zu bleiben. Wenn nicht alle koordinierten Änderungen durchgeführt werden, ist dies inkonsistent und ein Fehler.

  2. Beheben Sie Problem 1, indem Sie Benachrichtigungsmethoden einfügen. Wenn Teil A geändert wird, werden die erforderlichen Änderungen an Teil B und C weitergegeben. Dies ist der Hauptgrund, weshalb die Verwendung von get-and-set-Zugriffsmethoden empfohlen wird. Da dies eine empfohlene Vorgehensweise ist, scheint sie Problem 1 zu entschuldigen, was mehr zu Problem 1 und mehr zu Lösung 2 führt. Dies führt nicht nur zu Fehlern aufgrund der unvollständigen Implementierung der Benachrichtigungen, sondern auch zu einem leistungsbeeinträchtigenden Problem bei außer Kontrolle geratenen Benachrichtigungen. Dies sind keine unendlichen Berechnungen, sondern nur sehr lange.

Diese Konzepte werden als gute Dinge gelehrt, im Allgemeinen von Lehrern, die nicht in Monster-Apps mit Millionen von Zeilen arbeiten mussten, die sich mit diesen Problemen befassen.

Folgendes versuche ich zu tun:

  1. Halten Sie die Daten so normal wie möglich, damit Änderungen an den Daten an möglichst wenigen Codepunkten vorgenommen werden, um die Wahrscheinlichkeit zu minimieren, in einen inkonsistenten Zustand zu wechseln.

  2. Verwenden Sie Benachrichtigungen nicht, wenn Daten nicht normalisiert werden müssen und Redundanz unvermeidbar ist, um die Konsistenz zu gewährleisten. Dulden Sie eher vorübergehende Inkonsistenzen. Beheben Sie Inkonsistenzen mit periodischen Durchläufen der Daten durch einen Prozess, der nur dies tut. Dies zentralisiert die Verantwortung für die Aufrechterhaltung der Konsistenz und vermeidet gleichzeitig die Leistungs- und Korrektheitsprobleme, für die Benachrichtigungen anfällig sind. Dies führt zu Code, der viel kleiner, fehlerfrei und effizienter ist.


3

Diese Art von Klassen ist aus folgenden Gründen sehr nützlich, wenn Sie sich mit mittelgroßen / großen Anwendungen befassen:

  • Es ist ganz einfach, einige Testfälle zu erstellen und sicherzustellen, dass die Daten konsistent sind.
  • Es enthält alle Arten von Verhaltensweisen, die diese Informationen beinhalten, sodass die Zeit für die Verfolgung von Datenfehlern reduziert wird
  • Ihre Verwendung sollte die Methodenkomponenten leichtgewichtig halten.
  • Bei Verwendung von ORMs bietet diese Klasse Flexibilität und Konsistenz. Wenn Sie ein komplexes Attribut hinzufügen, das anhand einfacher Informationen berechnet wurde, die sich bereits in der Klasse befinden, wird eine einfache Methode geschrieben. Dies ist sehr viel flexibler und produktiver, als wenn Sie Ihre Datenbank überprüfen und sicherstellen müssen, dass alle Datenbanken mit neuen Änderungen gepatcht wurden.

Zusammenfassend sind sie meiner Erfahrung nach in der Regel nützlicher als ärgerlich.


3

Beim Spieledesign lohnt es sich manchmal, Klassen zu haben, die nur Daten speichern, und andere Klassen, die alle Nur-Daten-Klassen durchlaufen, um die Logik auszuführen.


3

Stimme dem Anna Lear zu,

Auf keinen Fall böse und kein Codegeruch in meinem Kopf. Datencontainer sind gültige OO-Bürger. Manchmal möchten Sie zusammengehörige Informationen zusammenfassen. Es ist viel besser, eine Methode zu haben wie ...

Manchmal vergessen die Leute, die Java-Kodierungskonventionen von 1999 zu lesen, was sehr deutlich macht, dass diese Art der Programmierung vollkommen in Ordnung ist. In der Tat, wenn Sie es vermeiden, dann wird Ihr Code riechen! (zu viele Getter / Setter)

Aus Java Code Conventions 1999: Ein Beispiel für geeignete öffentliche Instanzvariablen ist der Fall, in dem die Klasse im Wesentlichen eine Datenstruktur ohne Verhalten ist. Mit anderen Worten, wenn Sie eine Struktur anstelle einer Klasse verwendet hätten (sofern Java diese unterstützt), ist es angebracht, die Instanzvariablen der Klasse öffentlich zu machen. http://www.oracle.com/technetwork/java/javase/documentation/codeconventions-137265.html#177

Bei richtiger Verwendung sind PODs (einfache alte Datenstrukturen) besser als POJOs, genauso wie POJOs oft besser als EJBs sind.
http://en.wikipedia.org/wiki/Plain_Old_Data_Structures


3

Strukturen haben auch in Java ihren Platz. Sie sollten sie nur verwenden, wenn die folgenden beiden Dinge zutreffen:

  • Sie müssen nur Daten aggregieren, die kein Verhalten aufweisen, z. B. als Parameter übergeben
  • Es spielt keine Rolle, welche Art von Werten die aggregierten Daten haben

Wenn dies der Fall ist, sollten Sie die Felder öffentlich machen und die Getter / Setter überspringen. Getter und Setter sind sowieso klobig, und Java ist albern, weil es keine Eigenschaften wie eine nützliche Sprache hat. Da Ihr strukturähnliches Objekt ohnehin keine Methoden haben sollte, sind öffentliche Felder am sinnvollsten.

Wenn jedoch eine dieser Bedingungen nicht zutrifft, haben Sie es mit einer echten Klasse zu tun. Das bedeutet, dass alle Felder privat sein sollten. (Wenn Sie unbedingt ein Feld mit einem besser zugänglichen Bereich benötigen, verwenden Sie einen Getter / Setter.)

Um zu überprüfen, ob sich Ihre mutmaßliche Struktur verhält, prüfen Sie, wann die Felder verwendet werden. Wenn es gegen Tell zu verstoßen scheint, fragen Sie nicht , dann müssen Sie dieses Verhalten in Ihre Klasse verschieben.

Wenn sich einige Ihrer Daten nicht ändern sollten, müssen Sie alle Felder endgültig ausfüllen. Sie könnten erwägen, Ihre Klasse unveränderlich zu machen . Wenn Sie Ihre Daten validieren müssen, geben Sie die Validierung in den Setters und Konstruktoren an. (Ein nützlicher Trick besteht darin, einen privaten Setter zu definieren und Ihr Feld in Ihrer Klasse nur mit diesem Setter zu ändern.)

Ihr Bottle-Beispiel würde höchstwahrscheinlich beide Tests nicht bestehen. Sie könnten (erfundenen) Code haben, der so aussieht:

public double calculateVolumeAsCylinder(Bottle bottle) {
    return bottle.height * (bottle.diameter / 2.0) * Math.PI);
}

Stattdessen sollte es sein

double volume = bottle.calculateVolumeAsCylinder();

Wenn Sie die Höhe und den Durchmesser ändern würden, wäre es die gleiche Flasche? Wahrscheinlich nicht. Die sollten endgültig sein. Ist ein negativer Wert für den Durchmesser in Ordnung? Muss Ihre Flasche größer sein als breit? Kann das Cap null sein? Nein? Wie validieren Sie das? Angenommen, der Kunde ist entweder dumm oder böse. ( Es ist unmöglich, den Unterschied zu erkennen. ) Sie müssen diese Werte überprüfen.

So könnte Ihre neue Flaschenklasse aussehen:

public class Bottle {

    private final int height, diameter;

    private Cap capType;

    public Bottle(final int height, final int diameter, final Cap capType) {
        if (diameter < 1) throw new IllegalArgumentException("diameter must be positive");
        if (height < diameter) throw new IllegalArgumentException("bottle must be taller than its diameter");

        setCapType(capType);
        this.height = height;
        this.diameter = diameter;
    }

    public double getVolumeAsCylinder() {
        return height * (diameter / 2.0) * Math.PI;
    }

    public void setCapType(final Cap capType) {
        if (capType == null) throw new NullPointerException("capType cannot be null");
        this.capType = capType;
    }

    // potentially more methods...

}

0

IMHO gibt es oft nicht genug Klassen wie diese in stark objektorientierten Systemen. Ich muss das sorgfältig abschätzen.

Wenn die Datenfelder einen großen Umfang und eine große Sichtbarkeit haben, kann dies natürlich äußerst unerwünscht sein, wenn in Ihrer Codebasis Hunderte oder Tausende Stellen vorhanden sind, an denen solche Daten manipuliert werden. Das verlangt nach Schwierigkeiten und Schwierigkeiten, Invarianten aufrechtzuerhalten. Gleichzeitig bedeutet dies jedoch nicht, dass jede einzelne Klasse in der gesamten Codebasis vom Verbergen von Informationen profitiert.

Es gibt jedoch viele Fälle, in denen solche Datenfelder einen sehr engen Bereich haben. Ein sehr einfaches Beispiel ist eine private NodeKlasse einer Datenstruktur. Es kann den Code oftmals erheblich vereinfachen, indem die Anzahl der laufenden Objektinteraktionen verringert wird, wenn diese Nodeeinfach aus Rohdaten bestehen könnten. Dies dient als Entkopplungsmechanismus, da die alternative Version möglicherweise eine bidirektionale Kopplung beispielsweise von Tree->Nodeund Node->Treeim Gegensatz zu einfach erfordert Tree->Node Data.

Ein komplexeres Beispiel wären Entity-Component-Systeme, wie sie häufig in Game-Engines verwendet werden. In diesen Fällen handelt es sich bei den Komponenten häufig nur um Rohdaten und Klassen wie die, die Sie gezeigt haben. Ihr Umfang / ihre Sichtbarkeit ist jedoch tendenziell begrenzt, da normalerweise nur ein oder zwei Systeme auf diesen bestimmten Komponententyp zugreifen können. Infolgedessen fällt es Ihnen immer noch leicht, Invarianten in diesen Systemen zu verwalten, und darüber hinaus treten bei solchen Systemen nur sehr wenige object->objectWechselwirkungen auf, sodass Sie leicht nachvollziehen können, was auf der Augenhöhe des Vogels vor sich geht.

In solchen Fällen können Sie in Bezug auf Interaktionen zu etwas Ähnlichem kommen (dieses Diagramm zeigt Interaktionen an, nicht die Kopplung, da ein Kopplungsdiagramm möglicherweise abstrakte Schnittstellen für das zweite Bild unten enthält):

Bildbeschreibung hier eingeben

... im Gegensatz dazu:

Bildbeschreibung hier eingeben

... und der frühere Systemtyp ist in der Regel viel einfacher zu warten und in Bezug auf die Richtigkeit zu begründen, obwohl die Abhängigkeiten tatsächlich in Richtung Daten fließen. Sie erhalten in erster Linie eine viel geringere Kopplung, da viele Dinge in Rohdaten umgewandelt werden können, anstatt dass Objekte miteinander interagieren und ein sehr komplexes Wechselwirkungsdiagramm bilden.


-1

Es gibt sogar viele seltsame Kreaturen in der OOP-Welt. Ich habe einmal eine Klasse erstellt, die abstrakt ist und nichts enthält, nur um ein gemeinsames Elternteil von zwei anderen Klassen zu sein ... es ist die Port-Klasse:

SceneMember 
Message extends SceneMember
Port extends SceneMember
InputPort extends Port
OutputPort extends Port

SceneMember ist also die Basisklasse und erledigt alle Aufgaben, die für die Darstellung in der Szene erforderlich sind: Hinzufügen, Löschen, Festlegen der ID usw. Die Nachricht ist die Verbindung zwischen den Ports. Sie hat ihr eigenes Leben. InputPort und OutputPort enthalten ihre eigenen I / O-spezifischen Funktionen.

Port ist leer. Es wird nur verwendet, um InputPort und OutputPort beispielsweise für eine Portliste zu gruppieren. Es ist leer, da SceneMember alle Elemente enthält, die als Member fungieren sollen, und InputPort und OutputPort die vom Port angegebenen Aufgaben enthalten. InputPort und OutputPort sind so unterschiedlich, dass sie keine gemeinsamen Funktionen (außer SceneMember) haben. Port ist also leer. Aber es ist legal.

Vielleicht ist es ein Gegenmuster , aber ich mag es.

(Es ist wie das Wort "Kumpel", das sowohl für "Ehefrau" als auch für "Ehemann" verwendet wird. Sie verwenden das Wort "Kumpel" niemals für eine konkrete Person, da Sie das Geschlecht der Person kennen und es keine Rolle spielt ob er verheiratet ist oder nicht, so verwenden Sie stattdessen "jemanden", der jedoch immer noch existiert und in seltenen, abstrakten Situationen verwendet wird, z. B. in einem Gesetzestext.)


1
Warum müssen Ihre Ports SceneMember erweitern? Warum nicht die Port-Klassen für SceneMembers erstellen?
Michael K

1
Warum also nicht das Standard-Markierungsschnittstellenmuster verwenden? Grundsätzlich identisch mit Ihrer leeren abstrakten Basisklasse, aber es ist eine viel gebräuchlichere Redewendung.
TMN

1
@Michael: Nur aus theoretischen Gründen habe ich Port für die zukünftige Verwendung reserviert, aber diese Zukunft ist noch nicht angekommen und wird es vielleicht nie. Mir war nicht klar, dass sie überhaupt keine Gemeinsamkeiten haben, anders als ihre Namen vermuten. Ich werde eine Entschädigung für alle zahlen, die Verluste durch diese leere Klasse erlitten haben ...
ern0

1
@TMN: SceneMember-Typen (abgeleitete Typen) haben die getMemberType () -Methode. Es gibt mehrere Fälle, in denen Scene nach einer Teilmenge von SceneMember-Objekten durchsucht wird.
ern0

4
Dies beantwortet die Frage nicht.
Eva
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.