| 

.NET C# Java Javascript Exception

1
Wenn man eine Gruppe und einzelne Elemente hat – wo fügt man dann die Add-Methode hinzu? Also heißt es administrators.Add(user) oder user.Add(administrators)? Gibt es da eine Best-Practice? Quasi immer vom kleineren zum größeren, oder umgekehrt?
News:
18.05.2011
Schnurrhaar 11 2
Auf die Beantwortung dieser Frage war ein Kopfgeld in Höhe von 50 Reputationspunkten ausgesetzt. Das Kopfgeld wurde bereits vergeben.
3 Antworten
1
Aus meiner Sicht ist es abhängig von der Semantik.

Sachverhalte:
1. In einem Benutzersystem können Benutzer mehreren Gruppen hinzugefügt werden. Wenn man eine Gruppe löscht, löscht man damit aber nicht die Benutzer, weil dies zu einer Inkonsistenz in den anderen Gruppen führen würde. Ein Benutzer kann in einem Berechtigungssystem durchaus ohne Gruppenzugehörigkeit existieren. Auf der anderen Seite kann ein Benutzer aber nicht ohne Benutzersystem leben. Es gibt also einfache Referenzen und existenzielle Abhängigkeiten, die dringend zu unterscheiden sind. Was die existenzielle Abhängigkeit angeht, sollte ein Objekt immer nur von genaum einem Objekt existenziell abhängig sein. Es dürfen aber mehrere Referenzen auf ein Objekt existieren.
2. Die Navigation über Assoziationen ist in sehr vielen Fällen "natürlich" (z.B. Benutzersystem.getAlleBenutzer()), in anderen Fällen sicherlich "erwünscht" (benutzer.getGruppenmitgliedschaften()) aber nicht essentiell, da die "erwünschten" Assoziationen meistens Abkürzungen sind für die "natürlichen" Assoziationen (hier Iteration über Benutzersystem.getGruppen() und gruppe.istMitglied(benutzer)).
3. Existenzielle Abhängigkeiten sind immer natürliche Assoziationen. Natürliche Assoziationen müssen aber nicht existenziell sein.


Vorschlag:
Es sollte immer von den natürlichen Assoziationen ausgegangen werden, weil diese die Klassen- und Objektstruktur zusammenhalten.
Die gewünschten Assoziationen (Abkürzungen) sind nachzupflegen und synchron zur natürlichen Struktur zu halten.

// natürlich, existenziell:

Benutzer benutzer = Benutzersystem.addBenutzer("einBenutzer");

// natürlich, nicht existenziell (nur Referenz):

gruppe.add(benutzer)

// erwünscht, nie existenziell aber konsistent zur natürlichen Struktur:

class Gruppe {

...

public void add(Benutzer benutzer) {

this.benutzer.add(benutzer) // lokale Liste

benutzer.addMitgliedschaft(gruppe) // konsistente Abkürzung bereitstellen

}

...

}


Anmerkungen:
1.
Gibt es da eine Best-Practice? Quasi immer vom kleineren zum größeren, oder umgekehrt?

Dein Gefühl, dem größeren Objekt die Verantwortung zuzutragen, ist in den meisten Fällen "natürlich" und hier absolut richtig gewesen. Dennoch sollte man immer schauen, welche Bedeutung die Objekte im fachlichen Kontext haben und daraus die Verantwortlichkeiten ableiten. Das Beispiel mit dem Benutzersystem ist da noch sehr einfach.

2. Manche perfomantere technische Umsetzung insbesondere in Hibernate erzwingt manchmal das Management der Assoziation von der verkehrten Seite. (Siehe hierzu Hibernate - Das Praxisbuch für Entwickler, Sebastian Hennebrüder, Galileo Computing, S.217 ff.). Mein Leitspruch bleibt aber: Semantic first, d.h. Die Technik muss sich der Fachlichkeit anpassen, nicht umgekehrt, auch wenn es manchmal etwas langsamer läuft.
18.05.2011
oopexpert 455 1 8
0
In allen mir bekannten Collection-APIs hat die Collection die Add-Methode. Daher würde ich zu administrators.Add(user) raten.
18.05.2011
carlptr 777 1 8
Das ganze geht auch problemlos umgekehrt wenn user ein Propertie hat "user.Gruppe = new List<IGruppen>();"
Dann geht und ist durchaus logisch und sinnvoll.
user.Gruppe.Add(administrators)
Floyd 18.05.2011
Klar geht das auch. Ich sage ja auch nicht, dass der User kein Property Groups haben darf.
Üblicher ist meiner Meinung aber, dass eine Methode "Add" auf der übergeordneten Klasse angeboten wird. Andernfalls würde ich eine Methode AddTo erwarten.
Es wird auch niemand gehindert in der Add-Methode der Klasse Gruppe in der User-Klasse das Groups-Property zu erweitern.
Also etwa
class Group
{
public Add(User user)
{
_users.Add(user);
user.Groups.Add(this);
}
}
Dann haben beide Objekte gegenseitig eine Referenz aufeinander.
carlptr 18.05.2011
"Üblicher ist meiner Meinung aber, dass eine Methode "Add" auf der übergeordneten Klasse angeboten wird." Und genau in diesem Punkt bin ich anderer Meinung. Erstens sollte "Add" immer noch von Collections (in welcher Form auch immer) angeboten werden. Dh. also administrators.users.Add(...) oder user.Gruppen.Add(...). Ich sehe keinen Sinn einer Klasse die keine Collection ist eine "Add"-Methode zu verpassen, es sei denn ich will wirklich rechnen. (z.b. "Point myPoint = new Point(1,1); myPoint.Add(new Point(5,5));")
Floyd 18.05.2011
Zudem ist es meiner Meinung nach ebenso wichtig den genauen Verwendungszweck zu berücksichtigen um an dieser Stelle keine Resourcen- und/oder Laufzeischleuder zu basteln. Es gibt für beide Varianten sinnvolle Anwendungszwecke.
Floyd 18.05.2011
Korrektur: "Erstens sollte "Add" immer NUR von Collections (in welcher Form auch immer) angeboten werden." meinte ich natürlich.

Vote for Edit-Funktion für Kommentare!!
Floyd 18.05.2011
Innerhalb der Klasse "Gruppe" user.groups.add(this) aufzurufen verstößt ersteinmal gegen das Geheimnisprinzip, weil Du deine Referenz veröffentlichst. Jeder kann an deinem User irgendeine Gruppe hinzufügen, weil Du die Collection herausreichst. Man kann sich dann mit Seiteneffekten herumärgern. Außerdem sollte der Benutzer die Hoheit über das Hinzufügen und entfernen seiner Mitgliedschaften haben, und nicht irgendwer, der irgendwann einmal die Referenz auf die Collection erhalten hat (Single Responsibility). Und wenn die Methode "add" nicht gefällt, einfach in "addGroup" umbenennen.
oopexpert 25.05.2011
@Floyd: soweit ich sehe, wurde das Kommentar-Edit-Feature abgelehnt, und man kann nicht mehr dafür voten :-((( Mist, dass ich das nicht früher gesehen habe.
Matthias Hlawatsch 25.05.2011
0
Das ist meißt von Fall zu Fall unterschiedlich und hängt in der Regel ganz davon ab was man erreichen möchte oder wie die Anforderungen aussehen.

Hier eine klare Aussage zu treffen ohne die Anforderungen und den Zweck zu kennen ist schwierig.

Hier stellt sich schon bei deinem einfachen Beispiel die Frage, was ist "user"? Wenn "user" eine einzelne Person ist müßte man dann nicht "user.Gruppe.Add(administrators)" schreiben anstatt "user.Add(administrators)"?!

Um auf dein Beispiel zurückzukommen und die verschiedenen Anwendungszwecke:

Wenn du in der Regel von den Gruppe auf die User schließen musst und du meißtens nur Gruppen und keine User als Ausgang hast ist die erste Variante schneller.

Wenn du hingegen eine Art Rechteverwaltung baust und somit meißt User hast und auf deren Gruppen schließen willst, ist die zweite Variante schneller.
18.05.2011
Floyd 14,6k 3 9
Floyd 14,6k 3 9
Das Schließen von der Gruppe auf die enthaltenen Benutzer würde ich immer anbieten (natürliche Assoziation). Das Schließen von einem Benutzer auf seine Mitgliedschaften wäre eine Abkürzung, die synchron gehalten werden muss. Meine Meinung rührt daher, weil ich der Auffassung bin, dass Benutzer ohne Gruppen "leben" können, während Gruppen ohne Benutzer wenig sinnvoll sind. Deshalb wiegt die Assoziation von einer Gruppe zu den Benutzern stärker, als die Asoziation eines Benutzers zu seinen Mitgliedschaften.
oopexpert 25.05.2011

Stelle deine .net-Frage jetzt!
TOP TECHNOLOGIES CONSULTING GmbH