Ich arbeite derzeit an einem System, auf dem Benutzer vorhanden sind und jeder Benutzer eine oder mehrere Rollen hat. Ist es eine gute Praxis, List of Enum-Werte für Benutzer zu verwenden? Ich kann mir nichts Besseres vorstellen, aber das fühlt sich nicht gut an.
enum Role{
Admin = 1,
User = 2,
}
class User{
...
List<Role> Roles {get;set;}
}
Antworten:
TL; DR: Es ist normalerweise eine schlechte Idee, eine Sammlung von Aufzählungen zu verwenden, da dies oft zu einem schlechten Design führt. Eine Auflistung von Aufzählungen erfordert normalerweise unterschiedliche Systementitäten mit einer bestimmten Logik.
Es ist notwendig, zwischen einigen Anwendungsfällen von Enum zu unterscheiden. Diese Liste ist nur von höchster Stelle, daher könnte es weitere Fälle geben ...
Die Beispiele sind alle in C #, ich nehme an, Ihre bevorzugte Sprache wird ähnliche Konstrukte haben, oder Sie könnten sie selbst implementieren.
1. Es ist nur ein einziger Wert gültig
In diesem Fall sind die Werte exklusiv, z
Es ist ungültig, eine Arbeit zu haben, die sowohl
Pending
als auch istDone
. Daher ist nur einer dieser Werte gültig. Dies ist ein guter Anwendungsfall für Enum.2. Eine Kombination von Werten ist gültig.
Dieser Fall wird auch als Flags bezeichnet. C # bietet
[Flags]
Enum-Attribute für die Arbeit mit diesen. Die Idee kann als eine Menge vonbool
s oderbit
s modelliert werden, von denen jedes einem Aufzählungsmitglied entspricht. Jedes Mitglied sollte einen Potenzwert von zwei haben. Kombinationen können mit bitweisen Operatoren erstellt werden:Das Verwenden einer Auflistung von Aufzählungselementen ist in einem solchen Fall ein Overkill, dass jedes Aufzählungselement nur ein Bit darstellt, das entweder gesetzt oder nicht gesetzt ist. Ich denke, die meisten Sprachen unterstützen solche Konstrukte. Andernfalls können Sie eine erstellen (z. B. verwenden
bool[]
und adressieren(1 << (int)YourEnum.SomeMember) - 1
).a) Alle Kombinationen sind gültig
Obwohl dies in einigen einfachen Fällen in Ordnung ist, ist eine Sammlung von Objekten möglicherweise geeigneter, da Sie häufig zusätzliche Informationen oder Verhaltensweisen benötigen, die auf dem Typ basieren.
(Hinweis: Dies setzt voraus, dass Sie sich nur wirklich für die Aromen des Eises interessieren - dass Sie das Eis nicht als eine Sammlung von Kugeln und Kegeln modellieren müssen.)
b) Einige Wertekombinationen sind gültig, andere nicht
Dies ist ein häufiges Szenario. Der Fall kann oft sein, dass Sie zwei verschiedene Dinge in eine Aufzählung setzen. Beispiel:
Jetzt , während es für beide vollständig gültig ist
Vehicle
undBuilding
habenDoor
s undWindow
s, es ist nicht sehr üblich ,Building
s habenWheel
s.In diesem Fall ist es besser, die Aufzählung in Teile aufzuteilen und / oder die Objekthierarchie zu ändern, um entweder Fall 1 oder 2a zu erreichen.
Überlegungen zum Entwurf
Irgendwie sind die Aufzählungen nicht die treibenden Elemente in OO, da der Typ einer Entität als ähnlich zu den Informationen angesehen werden kann, die normalerweise von einer Aufzählung bereitgestellt werden.
Nehmen Sie zB die
IceCream
Stichprobe aus # 2, dieIceCream
Entität würde anstelle von Flags eine Sammlung vonScoop
Objekten haben.Der weniger puristische Ansatz wäre,
Scoop
eineFlavor
Immobilie zu haben . Der puristische Ansatz wäre für dieScoop
eine abstrakte Basisklasse für seinVanillaScoop
,ChocolateScoop
stattdessen ... Klassen.Die Quintessenz lautet:
1. Nicht alles, was ein "Typ von etwas" ist, muss eine Aufzählung sein.
2. Wenn ein Aufzählungsmitglied in einem bestimmten Szenario kein gültiges Flag ist, sollten Sie die Aufzählung in mehrere verschiedene Aufzählungen aufteilen.
Nun zu deinem Beispiel (leicht verändert):
Ich denke, dieser genaue Fall sollte modelliert werden als (Anmerkung: nicht wirklich erweiterbar!):
Mit anderen Worten - es ist implizit, dass das ein
User
istUser
, die zusätzliche Information ist, ob er ein istAdmin
.Wenn Sie mehrere Rollen bekommen haben , die nicht exklusiv sind (zB
User
kann seinAdmin
,Moderator
,VIP
, ... zur gleichen Zeit), das wäre ein guter Zeitpunkt , um entweder Fahnen zu verwenden Enum oder eine abtract Basisklasse oder Schnittstelle.Die Verwendung einer Klasse zur Darstellung von a
Role
führt zu einer besseren Aufteilung von Verantwortlichkeiten, wenn aRole
die Verantwortung haben kann, zu entscheiden, ob es eine bestimmte Aktion ausführen kann.Mit einer Aufzählung müssten Sie die Logik für alle Rollen an einem Ort haben. Was den Zweck von OO zunichte macht und dich zum Imperativ zurückbringt.
Stellen Sie sich vor, dass a
Moderator
Bearbeitungsrechte hat undAdmin
sowohl über Bearbeitungs- als auch über Löschrechte verfügt.Enum-Ansatz (aufgerufen,
Permissions
um Rollen und Berechtigungen nicht zu mischen):Klasse Ansatz (dies ist alles
IAction
andere als perfekt, im Idealfall möchten Sie die in einem Besuchermuster, aber dieser Beitrag ist bereits enorm ...):Die Verwendung einer Aufzählung kann jedoch ein akzeptabler Ansatz sein (z. B. Leistung). Die Entscheidung hier hängt von den Anforderungen des modellierten Systems ab.
quelle
[Flags]
impliziert , dass alle Kombinationen mehr gültig sind, als ein Int impliziert, dass alle vier Milliarden Werte dieses Typs gültig sind. Es bedeutet einfach, sie können in einem einzigen Feld kombiniert werden - irgendwelche Beschränkungen für Kombinationen gehören zu höherer Ebene Logik.[Flags]
, sollten Sie die Werte auf Zweierpotenzen setzen, da dies sonst nicht wie erwartet funktioniert.Warum nicht Set verwenden? Wenn Sie Liste verwenden:
Wenn Sie sich Gedanken über die Leistung machen, gibt es zum Beispiel in Java ein
EnumSet
Array mit Booleschen Werten fester Länge (das i'te Boolesche Element beantwortet die Frage, ob der i'te Enum-Wert in dieser Menge vorhanden ist oder nicht). Zum BeispielEnumSet<Role>
. Siehe auchEnumMap
. Ich vermute, dass C # etwas ähnliches hat.quelle
EnumSet
s als Bitfelder implementiert.HashSet<MyEnum>
vs. Flags Aufzählungen: stackoverflow.com/q/9077487/87698FlagsAttribute
, mit dem Sie bitweise Operatoren verwenden können, um Aufzählungen zu verketten. Klingt ähnlich wie JavaEnumSet
. msdn.microsoft.com/en-US/LIBRARY/system.flagsattribute BEARBEITEN : Ich hätte eine Antwort nach unten schauen sollen! es hat ein gutes Beispiel dafür.Schreiben Sie Ihre Aufzählung, damit Sie sie kombinieren können. Mit dem Exponential zur Basis 2 können Sie alle in einer Aufzählung kombinieren, 1 Eigenschaft haben und nach ihnen suchen. Ihre Aufzählung sollte dies lile sein
quelle
EnumSet
welche implementiert dies fürenum
s. Sie haben alle Booleschen Arithmetiken bereits abstrahiert und einige andere Methoden, um die Verwendung zu vereinfachen, sowie einen kleinen Speicher und eine gute Leistung.[flags]
Attribut, das @ Zdeněk Jelínek in seinem Beitrag untersucht .Kurze Antwort : Ja
Besser kurze Antwort : Ja, die Aufzählung definiert etwas in der Domain.
Antwort zur Entwurfszeit : Erstellen und verwenden Sie Klassen, Strukturen usw., die die Domäne in Bezug auf die Domäne selbst modellieren.
Antwort zur Codierungszeit : So codieren Sie Sling-Enums ...
Die gefolgerten Fragen :
Soll ich Zeichenfolgen verwenden?
Soll ich eine andere Klasse benutzen?
Ist die
Role
Aufzählungsliste , die zur Verwendung inUser
?WTF Bob?
Dies ist eine Entwurfsfrage, die in Programmiersprachentechniken eingebettet ist.
enum
ist ein guter Weg, um "Rollen" in Ihrem Modell zu definieren. EinList
Rollenwechsel ist also eine gute Sache.enum
ist Saiten weit überlegen.Role
ist eine Deklaration ALLER Rollen, die in der Domäne vorhanden sind."A"
"d"
"m"
"i"
"n"
in dieser Reihenfolge. Es ist nichts , was die Domain betrifft.Alle Klassen, die Sie entwerfen, um das Konzept einer
Role
bestimmten Lebensfunktionalität zu vermitteln, können dieRole
Aufzählung gut nutzen .Role
Eigenschaft, die angibt, um welche Art von Rolle es sich bei dieser Klasseninstanz handelt.User.Roles
Liste ist sinnvoll, wenn wir keine instanziierten Rollenobjekte benötigen oder wollen.RoleFactory
Klasse mitzuteilen . und nicht unwesentlich für den Codeleser.quelle
Das habe ich nicht gesehen, aber ich sehe keinen Grund, warum es nicht funktionieren würde. Vielleicht möchten Sie eine sortierte Liste verwenden, um sich jedoch gegen Dupes zu verteidigen.
Ein üblicherer Ansatz ist eine einzelne Benutzerebene, z. B. System, Administrator, Hauptbenutzer, Benutzer usw. Das System kann alles ausführen, die meisten Dinge verwalten und so weiter.
Wenn Sie die Werte von Rollen als Zweierpotenzen festlegen, können Sie die Rolle als Int speichern und die Rollen ableiten, wenn Sie sie wirklich in einem einzelnen Feld speichern möchten, aber dies ist möglicherweise nicht für jeden Geschmack geeignet.
So könnten Sie haben:
Wenn ein Benutzer also einen Rollenwert von 6 hat, hat er die Rollen "Front Office" und "Warehouse".
quelle
Verwenden Sie HashSet, da es Duplikate verhindert und über mehr Vergleichsmethoden verfügt
Ansonsten gute Verwendung von Enum
Hinzufügen einer Methode Boolean IsInRole (Role R)
und ich würde das Set überspringen
quelle
Das vereinfachte Beispiel, das Sie geben, ist in Ordnung, aber in der Regel ist es komplizierter. Wenn Sie beispielsweise die Benutzer und Rollen in einer Datenbank beibehalten möchten, sollten Sie die Rollen in einer Datenbanktabelle definieren, anstatt Aufzählungen zu verwenden. Das gibt Ihnen referentielle Integrität.
quelle
Wenn ein System - sei es eine Software, ein Betriebssystem oder eine Organisation - Rollen und Berechtigungen behandelt, kann es sinnvoll sein, Rollen hinzuzufügen und Berechtigungen für diese zu verwalten.
Wenn dies durch Ändern des Quellcodes archiviert werden kann, kann es in Ordnung sein, sich an Aufzählungen zu halten. Aber irgendwann möchte der Benutzer des Systems in der Lage sein, Rollen und Berechtigungen zu verwalten. Dann werden Aufzählungen unbrauchbar.
Stattdessen möchten Sie eine konfigurierbare Datenstruktur haben. dh eine UserRole-Klasse, die auch eine Reihe von Berechtigungen enthält, die der Rolle zugewiesen sind.
Eine Benutzerklasse würde eine Reihe von Rollen haben. Wenn die Berechtigung des Benutzers überprüft werden muss, wird ein Zusammenfassungssatz aller Rollenberechtigungen erstellt und überprüft, ob die betreffende Berechtigung enthalten ist.
quelle