17 Stimmen

Ist es eine gute Praxis, Domain-Objekte als Schlüssel zu verwenden?

Ist es eine gute Praxis, Domänenobjekte als Schlüssel für Maps (oder "get"-Methoden) zu verwenden, oder ist es besser, nur die id des Domänenobjekts zu verwenden?

Es ist einfacher, dies anhand eines Beispiels zu erklären. Nehmen wir an, ich habe eine Person-Klasse, eine Club-Klasse und eine Membership-Klasse (die die anderen beiden verbindet). D.h.,

public class Person {
    private int id; // Primärschlüssel
    private String name;
}

public class Club {
    private String name; // Primärschlüssel
}

public class Membership {
    private Person person;
    private Club club;
    private Date expires;
}

Oder so ähnlich. Jetzt möchte ich eine Methode getMembership zu Club hinzufügen. Die Frage ist, sollte diese Methode ein Person-Objekt übergeben:

public Membership getMembership(Person person);

oder die id einer Person:

public Membership getMembership(int personId);

Was ist am idiomatischsten, was ist am bequemsten, was ist am passendsten?

Edit: Viele sehr gute Antworten. Ich habe mich dafür entschieden, die id nicht zu offenbaren, da die "Person" (wie Sie vielleicht gemerkt haben, hat meine eigentliche Domäne nichts mit Personen und Clubs zu tun...) Instanzen leicht verfügbar sind, aber vorerst intern in einem HashMap gespeichert werden, gehasht auf der id - aber zumindest ich offenbare sie korrekt in der Schnittstelle.

5voto

dsmith Punkte 1938

Verwenden Sie nicht die IDs, Mann, das ist einfach eine schlechte Idee aus allen genannten Gründen. Sie werden sich selbst in ein Design einsperren. Lassen Sie mich ein Beispiel geben.

Derzeit definieren Sie Ihre Mitgliedschaft als Abbildung von Clubs auf Personen. Richtig, Ihre Mitgliedschaft sollte eine Zuordnung von Clubs zu "Mitgliedern" sein, aber Sie gehen davon aus, dass alle Mitglieder Personen sind und dass Sie einfach die ID verwenden können, da alle Personen-IDs eindeutig sind.

Aber was ist, wenn Sie in Zukunft Ihr Mitgliedschaftskonzept auf "Familienmitgliedschaften" erweitern möchten, für die Sie eine Familie-Tabelle und eine Familienklasse erstellen. In guter OO-Manier extrahieren Sie eine Schnittstelle von Familie und Person namens Mitglied. Solange beide Klassen die equals- und hashCode-Methoden ordnungsgemäß implementieren, muss kein anderer Code geändert werden. Persönlich hätte ich die Mitglied-Schnittstelle von Anfang an definiert.

public interface Mitglied {
}

public class Person implements Mitglied {
    private int id; // Primärschlüssel
    private String name;
}

public class Familie implements Mitglied {
   private int id;
   private String name;
}

public class Club {
    private String name; // Primärschlüssel
}

public class Mitgliedschaft {
   private Mitglied mitglied;
   private Club club;
   private Datum abläuft;
}

Wenn Sie IDs in Ihrer Schnittstelle verwendet hätten, müssten Sie entweder die Kreuztabellen-Eindeutigkeit der Schlüsselwerte durchsetzen oder zwei separate Maps pflegen und auf die schönen polymorphen Interface-Sachen verzichten.

Glauben Sie mir, es sei denn, Sie schreiben Einweg-, Wegwerf-Anwendungen, Sie möchten vermeiden, IDs in Ihrer Schnittstelle zu verwenden.

4voto

Ich denke, der erste Fall würde im Sinne dessen als "reiner" angesehen werden, dass die Methode getMembership möglicherweise spezifischere Daten von der Person selbst erfordern könnte, außer ihrer id (Angenommen, Sie kennen nicht die internen Abläufe der getMembership-Methode, obwohl dies wenig Sinn ergibt, da sie höchstwahrscheinlich im gleichen Bereich liegt).

Wenn sich herausstellt, dass tatsächlich Daten von der Person-Entity benötigt werden, wird keine DAO oder Factory für die betreffende Person benötigt.

Dies kann einfach aufgerufen werden, wenn Ihre Sprache und/oder Ihr ORM die Verwendung von Proxy-Objekten zulässt (und wenn Sie eine praktische Möglichkeit haben, diese Proxys zu erstellen).

Aber seien wir ehrlich. Wenn Sie nach einer Mitgliedschaft einer Person fragen, haben Sie höchstwahrscheinlich diese Person-Instanz bereits im Speicher, wenn Sie diese Methode aufrufen.

Weiter unten in der "Infrastruktur-Landschaft" gibt es auch diese Vorstellung von Implementierungsdetails, die Uri bereits erwähnt hat, während ich diese Antwort geschrieben habe (verdammt, das ging schnell, Alter!). Um genau zu sein, was ist, wenn Sie beschließen würden, dass dieses 'Person'-Konzept plötzlich einen zusammengesetzten Primärschlüssel/Identifikator in der zugrunde liegenden Datenbank hat... Würden Sie jetzt eine Identifizierungsklasse verwenden? Vielleicht den Proxy, über den wir gesprochen haben?

Kurzfassung

Die Verwendung von IDs ist kurzfristig wirklich einfacher, aber wenn Sie bereits ein solides ORM verwenden, sehe ich keinen Grund, nicht Proxys oder andere Mittel zu verwenden, um die objektorientierte Identität einer Entität auszudrücken, die keine Implementierungsdetails preisgibt.

4voto

Uri Punkte 86472

Angenommen, dies ist eine Datenbank-ID oder etwas, das nur zum Indexieren verwendet wird (anstatt einer Sozialversicherungsnummer), dann ist die Präsenz einer ID in einem idealen System ein Implementierungsdetail.

Als Implementierungsdetail würde ich bevorzugen, es in der Schnittstelle anderer Domänenobjekte zu verbergen. Somit bezieht sich die Mitgliedschaft im Wesentlichen auf Individuen und nicht auf Zahlen.

Natürlich würde ich sicherstellen, dass ich hashCode und equals() implementiert und gut dokumentiert habe, was sie bedeuten.

In diesem Fall würde ich ausdrücklich dokumentieren, dass die Gleichheit von zwei Person-Objekten allein auf der ID basiert. Dies ist ein etwas riskanter Vorschlag, macht den Code jedoch lesbarer, wenn Sie sicherstellen können, dass dies zutrifft. Ich fühle mich wohler dabei, wenn meine Objekte unveränderlich sind, sodass ich am Ende des Programms tatsächlich nicht zwei Person-Objekte mit derselben ID, aber unterschiedlichen Namen habe.

3voto

Zak Punkte 24386

Wenn Sie wirklich objektorientiertes Design praktizieren, dann möchten Sie das Konzept des Informationsverstecks aufrufen. Sobald Sie interne Feldtypen des Person-Objekts in die öffentliche Schnittstelle der Methoden des Mitgliedschaftsobjekts einhängen, zwingen Sie externe Entwickler (Benutzer) Ihrer Objekte, alle Arten von Informationen darüber zu lernen, was ein Person-Objekt ist, wie es gespeichert ist und welche Art von ID es hat.

Noch besser wäre es, da eine Person Mitgliedschaften haben kann, warum hängen Sie nicht die Methode "getMemberships" an die Person-Klasse an. Es scheint viel logischer zu sein, eine Person zu fragen, welche Mitgliedschaften sie hat, als ein "Mitglied" zu fragen, welchen Clubs eine bestimmte Person angehören könnte...

Bearbeiten - da der OP angegeben hat, dass es ihm um die Mitgliedschaft selbst geht und nicht nur als Beziehung zwischen Person und Club verwendet wird, aktualisiere ich meine Antwort.

Kurz gesagt, die "Club"-Klasse, die Sie definieren, wird jetzt gebeten, sich wie ein "Club-Roster" zu verhalten. Ein Verein hat ein Roster, es ist keine Roster. Ein Roster könnte mehrere Funktionen haben, darunter Möglichkeiten, Personen zu suchen, die dem Club angehören. Zusätzlich zur Suche nach einer Person anhand ihrer Club-ID möchten Sie sie möglicherweise auch nach Sozialversicherungsnummer, Namen, Eintrittsdatum usw. suchen. Das sagt mir, dass es eine Methode in der Klasse "Club" namens getRoster() gibt, die eine Datenstruktur zurückgibt, die alle Personen im Club suchen kann. Nennen Sie es eine Sammlung. Die Frage ist dann, ob Sie die Methoden in den vorhandenen Sammlungsklassen verwenden können, um die bisher definierten Anforderungen zu erfüllen, oder ob Sie eine benutzerdefinierte Sammlungsteilklasse erstellen müssen, um die geeignete Methode zum Finden des Mitgliedschaftseintrags bereitzustellen.

Da Ihre Klassenhierarchie wahrscheinlich von einer Datenbank unterstützt wird und Sie wahrscheinlich darüber sprechen, wie Informationen aus der Datenbank geladen werden, und nicht unbedingt die gesamte Sammlung erhalten möchten, um nur eine Mitgliedschaft zu erhalten, möchten Sie möglicherweise eine neue Klasse erstellen. Diese Klasse könnte, wie gesagt, "Roster" heißen. Sie würden die Instanz davon aus dem Aufruf von getRoster() in der Klasse "Club" erhalten. Sie würden "Suchmethoden" basierend auf allen Suchkriterien hinzufügen, die Sie wollten, die "öffentlich verfügbare" Informationen über die Person sind.. Namen, Club-ID, Personen-ID, Sozialversicherungsnummer, usw...

Meine ursprüngliche Antwort gilt nur, wenn die "Mitgliedschaft" rein eine Beziehung ist, um anzuzeigen, welchen Clubs welche Personen angehören.

1voto

Frank Schwieterman Punkte 23718

Ich würde wahrscheinlich IDs verwenden. Warum? Indem ich IDs übernehme, treffe ich sicherere Annahmen über den Aufrufer.

Wenn ich eine ID habe, wie viel Aufwand ist es, um die Person zu erhalten? Es könnte 'einfach' sein, erfordert aber den Zugriff auf einen Datenspeicher, was langsam ist...

Wenn ich ein Person-Objekt habe, wie viel Aufwand ist es, um die ID zu erhalten? Einfacher Zugriff auf ein Element. Schnell und verfügbar.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X