TL; DR: di solito è una cattiva idea usare una raccolta di enumerazioni che spesso porta a un cattivo design. Una raccolta di enumerazioni di solito richiede entità di sistema distinte con una logica specifica.  
 È necessario distinguere tra alcuni casi d'uso di enum. Questa lista è solo in cima alla mia testa, quindi potrebbero esserci più casi ... 
 Gli esempi sono tutti in C #, immagino che la tua lingua di scelta avrà costrutti simili o sarebbe possibile implementarli tu stesso. 
  1. Solo il singolo valore è valido  
 In questo caso, i valori sono esclusivi, ad es. 
public enum WorkStates
{
    Init,
    Pending,
    Done
}
 Non è valido avere un lavoro che sia sia   Pending    che   Done   . Pertanto solo uno di questi valori è valido. Questo è un buon caso d'uso di enum. 
  2. Una combinazione di valori è valida  
Questo caso è anche chiamato flag, C # fornisce   [Flags]    enum attributo a lavorare con questi. L'idea può essere modellata come un insieme di   bool    s o   bit    s con ogni corrispondente a un membro enum. Ogni membro dovrebbe avere un valore di potere di due. Le combinazioni possono essere create utilizzando operatori bit a bit: 
[Flags]
public enum Flags
{
    None = 0,
    Flag0 = 1, // 0x01, 1 << 0
    Flag1 = 2, // 0x02, 1 << 1
    Flag2 = 4, // 0x04, 1 << 2
    Flag3 = 8, // 0x08, 1 << 3
    Flag4 = 16, // 0x10, 1 << 4
    AFrequentlyUsedMask = Flag1 | Flag2 | Flag4,
    All = ~0 // bitwise negation of zero is all ones
}
 L'utilizzo di una raccolta di membri di enum è eccessivo in tal caso, poiché ciascun membro enum rappresenta solo un bit impostato o non impostato. Credo che la maggior parte delle lingue supportino costrutti come questo. Altrimenti puoi crearne uno (ad esempio, usa   bool[]    e indirizzalo a   (1 << (int)YourEnum.SomeMember) - 1   ). 
  a) Tutte le combinazioni sono valide  
 Anche se in alcuni casi questi sono ok, una raccolta di oggetti potrebbe essere più appropriata in quanto spesso hai bisogno di informazioni o comportamenti aggiuntivi in base al tipo. 
[Flags]
public enum Flavors
{
    Strawberry = 1,
    Vanilla = 2,
    Chocolate = 4
}
public class IceCream
{
    private Flavors _scoopFlavors;
    public IceCream(Flavors scoopFlavors)
    {
        _scoopFlavors = scoopFlavors
    }
    public bool HasFlavor(Flavors flavor)
    {
        return _scoopFlavors.HasFlag(flavor);
    }
}
 (nota: questo presuppone che ti interessi solo i sapori del gelato - che non hai bisogno di modellare il gelato come una raccolta di palette e un cono) 
  b) Alcune combinazioni di valori sono valide e altre no  
 Questo è uno scenario frequente. Il caso potrebbe spesso essere che stai mettendo due cose diverse in un enum. Esempio: 
[Flags]
public enum Parts
{
    Wheel = 1,
    Window = 2,
    Door = 4,
}
public class Building
{
    public Parts parts { get; set; }
}
public class Vehicle
{
    public Parts parts { get; set; }
}
 Ora, mentre è completamente valido sia per   Vehicle    che   Building    per avere   Door    se   Window    s, non è usuale per   Building    s avere   Wheel    s. 
 In questo caso, sarebbe meglio suddividere l'enum in parti e / o modificare la gerarchia degli oggetti per ottenere il caso n. 1 o n. 2a). 
  Considerazioni sulla progettazione  
 In qualche modo, le enumerazioni tendono a non essere gli elementi guida di OO poiché il tipo di entità può essere considerato simile alle informazioni che di solito sono fornite da un enum. 
 Prendi per es. il campione   IceCream    di # 2, l'entità   IceCream    anziché i flag hanno una collezione di oggetti   Scoop   . 
 L'approccio meno purista sarebbe che   Scoop    avesse una proprietà   Flavor   . L'approccio purista sarebbe che   Scoop    fosse una classe base astratta per   VanillaScoop   ,   ChocolateScoop   , ... invece classi. 
 La linea di fondo è questa: 
1. Non tutto ciò che è un "tipo di qualcosa" deve essere enum 
2. Quando alcuni membri dell'enumerazione non sono un flag valido in alcuni scenari, prendi in considerazione la possibilità di suddividere l'enum in più enumerazioni distinte. 
 Ora per il tuo esempio (leggermente modificato): 
public enum Role
{
    User,
    Admin
}
public class User
{
    public List<Role> Roles { get; set; }
}
 Penso che questo caso esatto dovrebbe essere modellato come (nota: non proprio estendibile!): 
public class User
{
    public bool IsAdmin { get; set; }
}
 In altre parole - è implicito che   User    è un   User   , le informazioni aggiuntive sono se è un   Admin   . 
 Se si dispone di più ruoli che non sono esclusivi (ad esempio   User    può essere   Admin   ,   Moderator   ,   VIP   , ... allo stesso tempo), sarebbe un buon momento per usare enif flag o una classe base o un'interfaccia di base. 
 L'utilizzo di una classe per rappresentare   Role    comporta una migliore separazione delle responsabilità in cui una   Role    può avere la responsabilità di decidere se può eseguire una determinata azione. 
 Con un enum avresti bisogno di avere la logica in un posto per tutti i ruoli. Che sconfigge lo scopo di OO e ti riporta indietro all'imperativo. 
 Immagina che   Moderator    abbia diritti di modifica e   Admin    abbia entrambi i diritti di modifica ed eliminazione. 
 Approccio Enum (chiamato   Permissions    per non mescolare ruoli e permessi): 
[Flags]
public enum Permissions
{
    None = 0
    CanEdit = 1,
    CanDelete = 2,
    ModeratorPermissions = CanEdit,
    AdminPermissions = ModeratorPermissions | CanDelete
}
public class User
{
    private Permissions _permissions;
    public bool CanExecute(IAction action)
    {
        if (action.Type == ActionType.Edit && _permissions.HasFlag(Permissions.CanEdit))
        {
            return true;
        }
        if (action.Type == ActionType.Delete && _permissions.HasFlag(Permissions.CanDelete))
        {
            return true;
        }
        return false;
    }
}
 Approccio di classe (questo è lontano dall'essere perfetto, idealmente, vorrai   IAction    in uno schema di visitatore ma questo post è già enorme ...): 
public interface IRole
{
    bool CanExecute(IAction action);
}
public class ModeratorRole : IRole
{
    public virtual bool CanExecute(IAction action)
    {
         return action.Type == ActionType.Edit;
    }
}
public class AdminRole : ModeratorRole
{
     public override bool CanExecute(IAction action)
     {
         return base.CanExecute(action) || action.Type == ActionType.Delete;
     }
}
public class User
{
    private List<IRole> _roles;
    public bool CanExecute(IAction action)
    {
        _roles.Any(x => x.CanExecute(action));
    }
}
 L'uso di un enum può essere un approccio accettabile sebbene (ad esempio, le prestazioni). La decisione qui dipende dai requisiti del sistema modellato.