I have an IUserRole
interface that represents different user role implementations, such as NormalUser
and Administrator
. Each user user role implementation allows checking for specific permissions that it allows. Example:
public class Program
{
enum UserPermission { Permission1, Permission2 }
interface IUserRole
{
bool HasPermission(UserPermission perm);
}
class NormalUser : IUserRole
{
private static readonly List<UserPermission> _permissions = new()
{
UserPermission.Permission1
};
public bool HasPermission(UserPermission perm)
{
return _permissions.Any(x => x == perm);
}
}
class Administrator : IUserRole
{
private static readonly List<UserPermission> _permissions = new()
{
UserPermission.Permission1,
UserPermission.Permission2
};
public bool HasPermission(UserPermission perm)
{
return _permissions.Any(x => x == perm);
}
}
public static void Main()
{
IUserRole role = new Administrator();
var hasPermission = role.HasPermission(UserPermission.Permission1);
Console.WriteLine($"Has Permission: {hasPermission}");
}
}
I wanted to avoid using enums here because it, to me, violates open/closed principle. The code smell is that the enum is not finite or fixed. Permissions can evolve over time, so I have to ask myself if I want to be adding to the enum each time.
An alternative I considered is this:
public class Program
{
interface IUserPermission {}
class Permission1 : IUserPermission {}
class Permission2 : IUserPermission {}
interface IUserRole
{
bool HasPermission<T>() where T : IUserPermission;
}
class NormalUser : IUserRole
{
private static readonly List<IUserPermission> _permissions = new()
{
new Permission1()
};
public bool HasPermission<T>() where T : IUserPermission
{
return _permissions.OfType<T>().Any();
}
}
class Administrator : IUserRole
{
private static readonly List<IUserPermission> _permissions = new()
{
new Permission1(),
new Permission2()
};
public bool HasPermission<T>() where T : IUserPermission
{
return _permissions.OfType<T>().Any();
}
}
public static void Main()
{
IUserRole role = new Administrator();
var hasPermission = role.HasPermission<Permission1>();
Console.WriteLine($"Has Permission: {hasPermission}");
}
}
This sort-of addresses the issue: I now can simply add a class instead of modifying an existing enum when I need to add new permissions. But overall this design is lacking:
- I still need to modify the
IUserRole
implementations to add support for new permissions. This makes any benefits to replacing the enum for something more open to extension nearly moot. - Using empty classes to represent permissions doesn't make me feel warm and fuzzy inside: It feels over engineered and abusive of classes which are classically supposed to represent behavior.
I started this with a specific question: What is the best alternative to enum here as to better respect/adhere to the open/closed principle? But the answer, I suspect, might be broader: The overall design probably needs attention. My whole approach feels wrong somehow.
Aucun commentaire:
Enregistrer un commentaire