luisobo
luisobo

Reputation: 664

Overlapping inheritance in Java

I have an inheritance hierarchy with overlap. The system knows about People that can be Clients, Providers and Agents. A person have to belong to one of these classes but can belong to two or three, i.e. one Person can be a Client and a Provider at the same time.

In the database I think that the problem is solved, one table per class (Person, Client, Provider and Agent table) and a Foreign Key from the Primary Key of the subclasses table to the Primary Key of the superclass table. (Any possible improvement will be welcome :) )

The problem comes in the Java world, I don't know the best way to map this database design to my Java POJOs. I have three possible grotty workarounds:

It's a webapp. I use hibernate + spring and GWT for the UI

The question is: which is the best way to solve this problem?

Upvotes: 2

Views: 2201

Answers (1)

Péter Török
Péter Török

Reputation: 116266

IMO inheritance is not the best way to model this, I would try composition instead.

You could have a Person class and several Role classes (implementing a common interface, or being members of a Role enum, depending on the context), with each person having one or more Roles attached.

This way you can add new role types easily, and dynamically attach/detach roles to/from a person. (You can also have persons without a role, should the need arise.)

Rough example:

interface Role {
  ...
}

final class Client implements Role {
  ...
}

final class Provider implements Role {
  ...
}

final class Agent implements Role {
  ...
}

class Person {
  List<Role> roles;
  public void addRole(Role role) { ... }
  public void removeRole(Role role) { ... }
  public Role getRoleOfType(Class<? extends Role> roleType) { ... }
}

Update: enum based example

This is applicable if the role objects have no state, thus you attach the same role instance(s) to every person.

enum Role {
  CLIENT,
  PROVIDER,
  AGENT;
  // possible members, constructor etc.
}

The Person class is almost the same as above, except that

  • I use an EnumSet instead of a List, since this is tailored specifically for enums,
  • getRoleOfType() makes no sense here, so I replaced it with hasRole().

    class Person {
      Set<Role> roles = new EnumSet<Role>();
      public void addRole(Role role) { ... }
      public void removeRole(Role role) { ... }
      public boolean hasRole(Role role) { ... }
    }
    

Upvotes: 12

Related Questions