First off, please note that doing something like entity.underlyingEntity.underlyingEntity.method()
is considered a code smell according to the Law of Demeter. This way, you're exposing a lot of implementation details to the consumer. And each need of extension or modification of such a system will hurt a lot.
So given that, I'd recommend you to have a HasRole
or IsAdmin
method on the User
as per CodesInChaos' comment. This way, the way how the roles are implemented on the user remains implementation detail for the consumer. And also it feels more natural to ask the user what his role is instead of asking him about details of his role and then deciding based on that.
Please also avoid using string
s unless where necessary. name
is a good example of string
variable because the contents are unknown beforehand. On the other hand, something like role
where you have two distinct values that are well known at compilation time, you'd better use strong typing. That's where enumeration type comes into play...
Compare
public bool HasRole(string role)
with
public enum Role { Admin, User }
public bool HasRole(Role role)
The second case gives me a lot more idea of what I should be passing around. It also prevents me from erroneously passing in an invalid string
in case I had no idea about your role constants.
Next is the decision on how will the role look. You can either use enum directly stored on the user:
public enum Role
{
Admin,
User
}
public class User
{
private Role _role;
public bool HasRole(Role role)
{
return _role == role;
}
// or
public bool IsAdmin()
{
return _role == Role.Admin;
}
}
On the other hand, if you want your role to have a behaviour itself, it should definitely again hide the details of how its type is being decided:
public enum RoleType
{
User,
Admin
}
public class Role
{
private RoleType _roleType;
public bool IsAdmin()
{
return _roleType == RoleType.Admin;
}
public bool IsUser()
{
return _roleType == RoleType.User;
}
// more role-specific logic...
}
public class User
{
private Role _role;
public bool IsAdmin()
{
return _role.IsAdmin();
}
public bool IsUser()
{
return _role.IsUser();
}
}
This is however quite verbose and the complexity would rise with each role addition - that's usually how the code ends up when you try to fully adhere to the Law of Demeter. You should improve the design, based on the concrete requirements of the system being modeled.
According to your question, I guess you'd better go with the first option with enum directly on User
. Should you need more logic on the Role
, the second option should be considered as a starting point.