1

I'm working on a project that requires several different users in the system, all of which have overlapping responsibilities; we've isolated two possible ways of tackling this problem, but we're unsure which of them are the most correct way of going about it.

Option 1: Create a virtual super-class for all the user-classes to inherit from. This super-class will have a boolean field for each of the responsibilities, allowing us to toggle which of the sub-classes have which responsibility.

  • Pros
    • One single class for all the sub-classes to inherit from, letting us toggle responsibilities via boolean fields
  • Cons:
    • It's essentially a god-class, which means it holds too much responsibility

Option 2: Create nineteen (19) interfaces, each representing one of the available responsibilities, and then have each of the user-classes inherit from this pool of interfaces in order to determine their responsibilities.

  • Pros
    • It allows us to seperate the concerns into several interfaces
  • Cons
    • We'll be in over our heads with interfaces, making it difficult to keep track of

So which is the best way of doing it, or is there perhaps a better way?

To elaborate my question I'm including the graphic below; it showcases the relations between the different parts of the system and the different users.

enter image description here

R means read access and RW means read + write access.

As you can see it's a bit of a mess of interlacing attributes.

2 Answers2

3

Option 3: Create individual objects corresponding to specific responsibilities, and then have each user hold a collection of these.

The collection of responsibilities for a user will contain only the responsibilities assigned to the user, i.e. you don't need an object to indicate the lack of a responsibility.

You worry it is "overkill" to create 19 classes for 19 responsibilities, but actually it is the simplest solution. If you indicate the same with 19 boolean fields on the base class, you have the same number of semantic entities, but a much more complex system overall, since each new responsibility increases the complexity of all user classes. By having the responsibilities as objects separate from the user, a new responsibility will not affect the user classes at all, but only the specific parts of the program which check for this specific responsibility.

Also, you can easily separate the assignment of responsibilities into a configuration. This would be quite tricky with option 1 and impossible with option 2.

Note: If you need to distinguish between read and read/write you need more that 19 boolean fields or 19 interfaces. For option 1 you need tri-state enumerations rather than booleans. For option 2 you need 38 distinct interfaces. For option 3 you can have a boolean flag on each responsibility which indicate if it is read or read/write.

JacquesB
  • 61,955
  • 21
  • 135
  • 189
3

I'd opt for option 3, use composition.

Depending on what you are doing with the responsibilities, you might be able to use an enum for them:

public enum Responsibilities
{
    Responsibility1,
    Responsibility2,
    ...
}

Then your user class might be something like:

public class User
{
    private List<Responsibilities> _responsibilities =
        List<Responsibilities>();

    public void AddResponsibility(Responsibilities responsibility) =>
        _responsibilities.Add(responsibility);

    public bool HasResponsibility(Responsibilities responsibility) =>
        responsibilities.Contains(responsibility);
}

If your need logic behind each responsibility, replace the enum with an IResponsibility interface and have each responsibility class implement that interface.

David Arno
  • 39,599
  • 9
  • 94
  • 129