views:

107

answers:

4

Hi,

I'm developing a system that has different types of users. Based upong their role, the system collects different information. I'm a little unsure how best to architect this.

At the base level I have a User entity which contains just the core info for a user. Beyond this, I need somewhere to store common information (not sure whether to add this to the User entity, create something like a Profile entity, or create a Member entity that extends the User entity).

After this, I then need somewhere to store the user type specific data. My roles are "Seller", "Merchant" and "Buyer". A User / Member can be one or more of these user types. I'm not sure here whether these should be seperate entities which extend the base User / Member, or whether these are more like extended profiles, which are a property on the User entity.

Could anybody sugest the best way to architect this?

A: 

I would start by making a separate interface for each: IUser, IMember, ISeller, IMerchant and IBuyer. Then I would create a separate Class and for each interface, which understands how to handle the CRUD for the instance (Create, Read, Update and Delete).

The nexus is the member. The IMember interface needs methods/propreties for IsSeller, IsMerchant and IsBuyer. If those return TRUE, the you know you can cast the Member object into the corresponding interfaces, or at least fetch the interface handler via a method. Note that the Member object always supports the IUser interface too.

That should get your started.

Mike Hanson
+2  A: 

Unless there's something fundamentally user-unrelated about the common information, you can store it into the user entity. For rôles, consider having separate entities linked to the user entity. This permits adding new rôles to a user (happens when somebody who has always been buying stuff suddenly decides to sell something), which the interface-based solution may have problems with (depending on your implementation language, of course).

An common pitfall is adding all rôle fields to the user entity. It works, but it tends to progress into unmaintainability as new rôles are added to the system.

dig
A: 

Depends if the available roles are fixed or fluid. Sounds like they're fixed, so you can:

  • define user.role as an int.
  • Define the roles as static ints to the power of two, e.g. Role.SELLER=1, Role.MERCHANT=2, Role.BUYER=4, and so on.
  • Add a hasRole() method to the user object that does a simple bitwise OR operation to determine if a user has a particular role.
Pete
+1  A: 

I just finished creating something very similar for a system I'm working on. The theory, in general, is to separate the definition (who they are) of an entity from its behaviour (roles; what they do). I also wanted to preserve the ability to query users based on the metadata contained in the roles that they are assigned to.

I ended up creating a Person class that looks like this:

class Person {
  Guid Id;
  ISet<Role> Roles;
  string Name; // and any other stuff a "person" might have

}

Next, I have an abstract Role class that looks like this:

abstract class Role {
  Guid Id;
  abstract string Name { get; } // implemented by concrete definitions of roles
  Person Person;
}

From this, I derive individual classes that "define" each role I have in my system. A User role would look something like this:

class User : Role {
  override string Name { get { return "User"; } }
  string LoginId;
  string Password;
  // etc.
}

Rinse and repeat for any other roles you might have.

At the ORM level (where I use NHibernate), I define UserRole as a joined-subclass of the Role entity.

The underlying assumptions behind this approach are:

  • Roles aren't dynamic.

There is no definition of roles at the data layer. A role exists simply because there's a class that derives from it.

  • You can't assign a role to the same person multiple times with different metadata

Well, in theory, I guess you could but it makes no sense for my particular system for a person to have two User roles assigned to them with different login ids and passwords.

Ragesh