В настоящее время я работаю в системе, где есть пользователи, и у каждого пользователя есть одна или несколько ролей. Является ли хорошей практикой использование списка значений Enum для пользователя? Я не могу придумать ничего лучшего, но с этим не все в порядке.
enum Role{
Admin = 1,
User = 2,
}
class User{
...
List<Role> Roles {get;set;}
}
Ответы:
TL; DR: Обычно плохая идея использовать коллекцию перечислений, так как это часто приводит к плохому дизайну. Коллекция перечислений обычно требует отдельных системных объектов с определенной логикой.
Необходимо различать несколько случаев использования enum. Этот список только в верхней части моей головы, поэтому может быть больше случаев ...
Все примеры написаны на C #, я думаю, у вашего языка будут схожие конструкции, или вы сможете реализовать их самостоятельно.
1. Допустимо только одно значение
В этом случае значения являются исключительными, например,
Недопустимо иметь какую-то работу, которая одновременно
Pending
иDone
. Поэтому только одно из этих значений является действительным. Это хороший пример использования enum.2. Допустима комбинация значений.
Этот случай также называется flags, C # предоставляет
[Flags]
атрибут enum для работы с ними. Идея может быть смоделирована как наборbool
s илиbit
s, каждый из которых соответствует одному члену перечисления. Каждый член должен иметь значение силы два. Комбинации могут быть созданы с использованием побитовых операторов:Использование коллекции членов перечисления является излишним в таком случае, поскольку каждый член перечисления представляет только один бит, который установлен или не установлен. Я думаю, что большинство языков поддерживают такие конструкции. В противном случае вы можете создать его (например, использовать
bool[]
и адресовать его(1 << (int)YourEnum.SomeMember) - 1
).а) Все комбинации действительны
Хотя в некоторых простых случаях это нормально, коллекция объектов может оказаться более подходящей, поскольку вам часто требуется дополнительная информация или поведение в зависимости от типа.
(примечание: это предполагает, что вы действительно заботитесь только о вкусах мороженого - вам не нужно моделировать мороженое как набор шариков и конуса)
б) Некоторые комбинации значений действительны, а некоторые нет
Это частый сценарий. Часто дело в том, что вы помещаете две разные вещи в одно перечисление. Пример:
Теперь, несмотря на то, что для s и s вполне допустимо
Vehicle
иBuilding
дляDoor
s, и дляWindow
s не очень обычноBuilding
иметьWheel
с.В этом случае было бы лучше разбить перечисление на части и / или изменить иерархию объектов, чтобы получить вариант № 1 или № 2а).
Особенности дизайна
Каким-то образом перечисления, как правило, не являются движущими элементами в ОО, поскольку тип сущности может считаться аналогичным информации, которую обычно предоставляет перечисление.
Возьмите, например,
IceCream
образец из # 2, уIceCream
объекта вместо флагов будет коллекцияScoop
объектов.Менее пуристом подход был бы для
Scoop
иметьFlavor
собственность. Пуристом подход был бы дляScoop
быть абстрактным базовым классом дляVanillaScoop
,ChocolateScoop
, ... классов вместо этого.Суть в том, что:
1. Не все, что является "типом чего-то", должно быть перечислением
2. Когда какой-либо член перечисления не является допустимым флагом в некотором сценарии, рассмотрите возможность разделения перечисления на несколько различных перечислений.
Теперь для вашего примера (немного изменено):
Я думаю, что этот точный случай должен быть смоделирован как (примечание: не очень расширяемый!):
Другими словами - подразумевается, что
User
этоUser
, дополнительная информация, является ли онAdmin
.Если вы иметь несколько ролей , которые не являются взаимоисключающими (например ,
User
может бытьAdmin
,Moderator
,VIP
, ... в то же время), что будет время хорошо использовать либо флаги ENUM или Abtract базовый класс или интерфейс.Использование класса для представления
Role
ведет к лучшему разделению обязанностей, когда у негоRole
может быть ответственность, чтобы решить, может ли он выполнить данное действие.С перечислением вам нужно было бы иметь логику в одном месте для всех ролей. Который побеждает цель ОО и возвращает вас к необходимости.
Представьте, что у вас
Moderator
есть права на редактирование иAdmin
редактирование, а также права на редактирование и удаление.Подход Enum (вызывается
Permissions
для того, чтобы не смешивать роли и разрешения):Классовый подход (это далеко не идеально, в идеале, вы хотели бы, чтобы
IAction
в шаблоне посетителя, но этот пост уже огромен ...):Использование перечисления может быть приемлемым подходом (например, производительность). Решение здесь зависит от требований моделируемой системы.
источник
[Flags]
подразумевается, что все комбинации действительны больше, чем int подразумевает, что все четыре миллиарда значений этого типа являются действительными. Это просто означает, что они могут быть объединены в одном поле - любые ограничения на комбинации принадлежат логике более высокого уровня.[Flags]
вы должны установить значения в степени двух, иначе это не будет работать, как ожидалось.Почему бы не использовать Set? При использовании списка:
Если вы беспокоитесь о производительности, то, например, в Java есть
EnumSet
реализация, которая реализована как массив логических значений фиксированной длины (i-й логический элемент отвечает на вопрос, присутствует ли значение i-го Enum в этом наборе или нет). Например,EnumSet<Role>
. Также смотритеEnumMap
. Я подозреваю, что в C # есть нечто подобное.источник
EnumSet
s реализованы как битовые поля.HashSet<MyEnum>
сравнению с перечислениями flags: stackoverflow.com/q/9077487/87698FlagsAttribute
, что позволяет использовать побитовые операторы для объединения перечислений. Похоже на JavaEnumSet
. msdn.microsoft.com/en-US/LIBRARY/system.flagsattribute РЕДАКТИРОВАТЬ: Я должен был посмотреть вниз один ответ! у этого есть хороший пример этого.Напишите ваше перечисление, чтобы вы могли объединить их. Используя экспоненциальную базу 2, вы можете объединить их все в одно перечисление, иметь 1 свойство и можете проверять их. Ваше перечисление должно быть
источник
EnumSet
который реализует это дляenum
s. У вас уже есть вся логическая арифметика, а также некоторые другие методы, облегчающие использование, плюс небольшая память и хорошая производительность.[flags]
атрибут, который @ Zdeněk Jelínek исследует в своем посте .Краткий ответ : да
Лучший ответ : да, enum определяет что-то в домене.
Ответ на этапе разработки: создание и использование классов, структур и т. Д., Которые моделируют домен с точки зрения самого домена.
Ответ на кодирование : вот как перебирать перечисления ...
Предполагаемые вопросы :
Должен ли я использовать строки?
Должен ли я использовать какой-то другой класс?
Role
Достаточно ли перечисления для использования вUser
?WTF Боб?
Это вопрос дизайна, который сформулирован в технических деталях языка программирования.
enum
хороший способ определить «роли» в вашей модели. Так чтоList
роль - это хорошо.enum
намного превосходит струны.Role
является декларацией ВСЕХ ролей, которые существуют в домене."A"
"d"
"m"
"i"
"n"
в указанном порядке. Это ничего, что касается домена.Любые классы, которые вы могли бы разработать, чтобы дать концепцию
Role
некоторой жизни - функциональность - могут эффективно использоватьRole
перечисление.Role
свойство, которое сообщает, какую роль выполняет этот экземпляр класса.User.Roles
Список является разумным , когда нам не нужно, или не хотят, конкретизированные объектов ролей.RoleFactory
классу; и, что немаловажно, читателю кода.источник
Это не то, что я видел, но я не вижу причин, почему это не сработало. Возможно, вы захотите использовать отсортированный список, поэтому он защищает от обманщиков.
Более распространенным подходом является однопользовательский уровень, например система, администратор, опытный пользователь, пользователь и т. Д. Система может делать все, администрировать большинство вещей и так далее.
Если бы вам нужно было установить значения ролей в виде степеней двух, вы могли бы сохранить роль в виде целого числа и получить роли, если вы действительно хотите хранить их в одном поле, но это может быть не всем по вкусу.
Таким образом, вы могли бы иметь:
Таким образом, если бы у пользователя было значение роли 6, тогда у него были бы роли Front office и Warehouse.
источник
Используйте HashSet поскольку он предотвращает дублирование и имеет больше методов сравнения
В противном случае хорошее использование Enum
Добавить метод Boolean IsInRole (Role R)
и я бы пропустил набор
источник
Упрощенный пример, который вы приводите, хорош, но обычно он более сложный, чем этот. Например, если вы собираетесь сохранить пользователей и роли в базе данных, вам следует определить роли в таблице базы данных, а не использовать перечисления. Это дает вам ссылочную целостность.
источник
Если система - может быть, программное обеспечение, операционная система или организация - имеет дело с ролями и разрешениями, наступает момент, когда полезно добавлять роли и управлять разрешениями для них.
Если это можно заархивировать, изменив исходный код, возможно, будет хорошо придерживаться перечислений. Но в какой-то момент пользователь системы хочет иметь возможность управлять ролями и разрешениями. Чем перечисления становятся непригодными.
Вместо этого вы захотите иметь настраиваемую структуру данных. то есть класс UserRole, который также содержит набор разрешений, назначенных роли.
Пользовательский класс будет иметь набор ролей. Если необходимо проверить разрешение пользователя, создается объединенный набор всех разрешений ролей и проверяется, содержит ли оно указанное разрешение.
источник