Je travaille actuellement sur un système où il y a des utilisateurs, et chaque utilisateur a un ou plusieurs rôles. Est-ce une bonne pratique d'utiliser les valeurs List of Enum sur User? Je ne peux penser à rien de mieux, mais cela ne me semble pas très bien.
enum Role{
Admin = 1,
User = 2,
}
class User{
...
List<Role> Roles {get;set;}
}
Réponses:
TL; DR: C'est généralement une mauvaise idée d'utiliser une collection d'énums car cela conduit souvent à une mauvaise conception. Un ensemble d'énums appelle généralement des entités système distinctes avec une logique spécifique.
Il est nécessaire de distinguer quelques cas d'utilisation de enum. Cette liste est seulement de tête, donc il pourrait y avoir plus de cas ...
Les exemples sont tous en C #, je suppose que votre langage de choix aura des constructions similaires ou il vous serait possible de les implémenter vous-même.
1. Seule la valeur unique est valide
Dans ce cas, les valeurs sont exclusives, par exemple
Il est invalide d'avoir un travail qui est à la fois
Pending
etDone
. Par conséquent, une seule de ces valeurs est valide. C’est un bon cas d’utilisation d’enum.2. Une combinaison de valeurs est valide
Ce cas est également appelé flags, C # fournit un
[Flags]
attribut enum pour travailler avec ceux-ci. L'idée peut être modélisée comme un ensemble debool
s oubit
s, chacun correspondant à un membre enum. Chaque membre devrait avoir une valeur de pouvoir de deux. Les combinaisons peuvent être créées à l'aide d'opérateurs au niveau du bit:L'utilisation d'une collection de membres enum est une surcharge, dans la mesure où chaque membre enum ne représente qu'un bit défini ou non défini. Je suppose que la plupart des langues supportent des constructions comme celle-ci. Sinon, vous pouvez en créer un (par exemple, utilisez
bool[]
et adressez-le par(1 << (int)YourEnum.SomeMember) - 1
).a) Toutes les combinaisons sont valables
Bien que cela soit correct dans certains cas simples, une collection d'objets peut être plus appropriée car vous avez souvent besoin d'informations supplémentaires ou d'un comportement basé sur le type.
(note: cela suppose que vous ne vous souciez que des saveurs de la glace - vous n'avez pas besoin de la modeler comme une collection de pelles et d'un cornet)
b) Certaines combinaisons de valeurs sont valides et d’autres non
C'est un scénario fréquent. Il arrive souvent que vous mettiez deux choses différentes dans une seule énumération. Exemple:
Maintenant, bien que ce soit tout à fait valable pour les deux
Vehicle
etBuilding
pour avoir desDoor
s etWindow
s, il n’est pas très courant queBuilding
s aitWheel
.Dans ce cas, il serait préférable de diviser l'énum en parties et / ou de modifier la hiérarchie des objets afin d'obtenir le cas n ° 1 ou n ° 2a).
Considérations sur la conception
D'une manière ou d'une autre, les enums ont tendance à ne pas être les éléments moteurs de OO car le type d'entité peut être considéré comme similaire aux informations habituellement fournies par une enum.
Prenons l'exemple de l'
IceCream
exemple n ° 2, l'IceCream
entité à la place des drapeaux aurait une collection d'Scoop
objets.L'approche moins puriste consisterait
Scoop
à avoir uneFlavor
propriété. L’approche puriste serait que leScoop
soit une classe de base abstraite pourVanillaScoop
,ChocolateScoop
... au lieu des cours.L'essentiel est que:
essentiel 1. Tout ce qui est un "type de quelque chose" ne doit pas forcément être enum
2. Si un membre enum n'est pas un indicateur valide dans certains scénarios, envisagez de fractionner l'énum en plusieurs enum distincts.
Maintenant, pour votre exemple (légèrement modifié):
Je pense que ce cas précis devrait être modélisé comme (note: pas vraiment extensible!):
En d'autres termes - il est implicite que le
User
est unUser
, l'info supplémentaire est de savoir s'il est unAdmin
.Si vous arrivez à avoir des rôles multiples qui ne sont pas exclusifs (par exemple ,
User
peut êtreAdmin
,Moderator
,VIP
... en même temps), ce serait un bon moment pour utiliser des drapeaux ENUM ou une classe de base abtract ou interface.L’utilisation d’une classe pour représenter un
Role
conduit à une meilleure séparation des responsabilitésRole
peut avoir la responsabilité de décider s'il peut ou non faire une action donnée.Avec un enum, vous auriez besoin de la logique en un seul endroit pour tous les rôles. Ce qui défait le but de OO et vous ramène à l'impératif.
Imaginez qu’un
Moderator
a des droits de modification etAdmin
modification et de droits de modification et de suppression.Approche Enum (appelée
Permissions
pour ne pas mélanger les rôles et les autorisations):Approche de classe (c'est loin d'être parfait, idéalement, vous voudriez le
IAction
dans un modèle de visiteur mais ce post est déjà énorme ...):L'utilisation d'un enum peut être une approche acceptable (performances). La décision dépend ici des exigences du système modélisé.
la source
[Flags]
implique que toutes les combinaisons sont valables, pas plus qu'un int ne suppose que les quatre milliards de valeurs de ce type sont valables. Cela signifie simplement qu'elles peuvent être combinées dans un seul champ - toute restriction sur les combinaisons appartient à la logique de niveau supérieur.[Flags]
, définissez les valeurs sur deux ou trois, sinon cela ne fonctionnera pas comme prévu.Pourquoi ne pas utiliser Set? Si vous utilisez la liste:
Si vous êtes préoccupé par les performances, alors, par exemple en Java, il existe
EnumSet
un tableau de booléens de longueur fixe (un élément booléen répond à la question de savoir si une valeur Enum est présente dans cet ensemble ou non). Par exemple,EnumSet<Role>
. Aussi, voirEnumMap
. Je soupçonne que C # a quelque chose de similaire.la source
EnumSet
les implémentations sont des champs de bits.HashSet<MyEnum>
drapeaux enums: stackoverflow.com/q/9077487/87698FlagsAttribute
, qui vous permet d’utiliser des opérateurs au niveau des bits pour concaténer des énumérations. Cela ressemble à JavaEnumSet
. msdn.microsoft.com/en-US/LIBRARY/system.flagsattribute EDIT: J'aurais dû regarder une réponse! cela en est un bon exemple.Écris ton enum pour pouvoir les combiner. En utilisant la base 2 exponentielle, vous pouvez les combiner tous dans une énumération, avoir une propriété et les vérifier. Votre enum devrait être un peu ça
la source
EnumSet
qui implémente cela pourenum
s. Toute l'arithmétique booléenne est déjà résumée, ainsi que d'autres méthodes facilitant son utilisation, une petite mémoire et de bonnes performances.[flags]
attribut, que @ Zdeněk Jelínek explore dans son message .Réponse courte : oui
Meilleure réponse courte : Oui, l'énumération définit quelque chose dans le domaine.
Réponse au moment de la conception : créez et utilisez des classes, des structures, etc. qui modélisent le domaine en termes de domaine lui-même.
Réponse du temps de codage : Voici comment coder des enumères ...
Les questions inférées :
Devrais-je utiliser des chaînes?
Devrais-je utiliser une autre classe?
La
Role
liste enum est-elle suffisante pour être utiliséeUser
?WTF Bob?
C'est une question de conception qui est encadrée dans les aspects techniques du langage de programmation.
enum
est un bon moyen de définir des "rôles" dans votre modèle. Alors, unList
rôle est une bonne chose.enum
est de loin supérieur aux cordes.Role
est une déclaration de TOUS les rôles existants dans le domaine."A"
"d"
"m"
"i"
"n"
, dans cet ordre. Ce n'est rien en ce qui concerne le domaine.Toute classe que vous pourriez concevoir pour donner le concept de
Role
vie - fonctionnalité - peut faire bon usage de l’Role
énumération.Role
propriété qui indique le type de rôle de cette instance de classe.User.Roles
liste est raisonnable lorsque nous n'avons pas besoin, ou ne voulons pas, d'objets de rôle instanciés.RoleFactory
classe; et non négligeable, au lecteur de code.la source
Ce n'est pas quelque chose que j'ai vu mais je ne vois aucune raison pour que cela ne fonctionne pas. Vous voudrez peut-être utiliser la liste triée pour la protéger contre les dupes.
Une approche plus courante est un niveau d'utilisateur unique, par exemple système, administrateur, utilisateur privilégié, utilisateur, etc. Le système peut tout faire, la plupart des tâches administratives, etc.
Si vous définissiez les valeurs de rôles comme des puissances à deux, vous pourriez stocker le rôle en tant qu'int et dériver les rôles si vous souhaitiez vraiment les stocker dans un seul champ, mais cela ne conviendrait peut-être pas à tout le monde.
Donc vous pourriez avoir:
Ainsi, si un utilisateur avait une valeur de rôle de 6, il aurait alors les rôles Front office et Warehouse.
la source
Utilisez HashSet, car il évite les doublons et a plus de méthodes de comparaison
Sinon bon usage de Enum
Ajouter une méthode Boolean IsInRole (rôle R)
et je sauterais l'ensemble
la source
L'exemple simpliste que vous donnez est correct, mais il est généralement plus compliqué que cela. Par exemple, si vous souhaitez conserver les utilisateurs et les rôles dans une base de données, vous devez définir les rôles dans une table de base de données plutôt que d'utiliser des énumérations. Cela vous donne une intégrité référentielle.
la source
Si un système - qu'il s'agisse d'un logiciel, d'un système d'exploitation ou d'une organisation - traite des rôles et des autorisations, il arrive un moment où il est utile d'ajouter des rôles et de gérer leurs autorisations.
Si cela peut être archivé en modifiant le code source, il serait peut-être correct de s'en tenir à des énumérations. Mais à un moment donné, l'utilisateur du système veut pouvoir gérer les rôles et les autorisations. Que des enums deviennent inutilisables.
Au lieu de cela, vous voudrez avoir une structure de données configurable. c'est-à-dire une classe UserRole qui contient également un ensemble d'autorisations assignées au rôle.
Une classe d'utilisateurs aurait un ensemble de rôles. S'il est nécessaire de vérifier l'autorisation de l'utilisateur, un ensemble d'unions de toutes les autorisations de rôles est créé et vérifié s'il contient l'autorisation en question.
la source