How to design an entity that has different fields depending on a type?

  softwareengineering

I have a specific domain entity that has a given type and some attributes. Based on the type, it can have another set of type-depending attributes. Normally, I would create a class for each type and define the type dependent attribute on the specific classes and the common attributes on the parent class:

class AbstractParentClass {
   commonAttribute1
   commonAttribute2
}

class TypeA extends AbstractParentClass {
   typeAAttribute1
   typeAAttrubute2
}

class TypeB extends AbstractParentClass {
   typeBAttribute1
   typeBAttribute2
}

However, I have close to 300 different types and creating 300 different subclasses seems like a huge amount of classes.

The other option that I have is create a field type in a class and then have all type-dependent attributes there:

class Entity {
   type
   commonAttribute1
   commonAttribute2
   typeAAttribute1
   typeAAttribute2
   typeBAttribute1
   typeBAttribute2
}

But this will be a pain to maintain and the business logic to make sure that only fields are set that are allowed to be set for a specific type will probably be a nightmare.

Are there any other options that I didn’t think about?

8

There is still another approach, which is to prefer composition over inheritance, and add the attributes dynamically as needed. Pseudo-code:

interface Component {
   componentName();
   getValue();
   setValue();  
}
 
class AbstractParentClass {
   commonAttribute1
   commonAttribute2
   commonBehavior1()
   addComponent(Component)
   getComponent(Name) 
   collection<Component> components
}

Of course, this design allows you create as many values as needed, without necessarily verifying consistency of the the attributes/components embedded individually. So some more thoughts are needed here.

If you push the thoughts to the extreme, you could even adopt the entity component system. This design pattern is popular in the gaming industry, because it avoids deep inflexible hierarchies and combinatorial explosion. The idea is then to have components that no longer represent a single attribute, but a group of attributes and/or behaviours.

1

Depending on how you’re going to use those fields, you can also use a HashMap. Situations in which this is useful:

  1. Accessing fields in a database table (column name will be a key) with unknown/high number of columns
  2. When you only care about some of the fields, but need to know the entire structure of the object

Example usage

public class HashMapExample<K, V> extends HashMap<K, V> {

final K important_field = ...;

public V getImportantField()
{
    return this.get(important_field);
}

public void setImportantField(V value)
{
    this.put(important_field ,value);
}

}

Usage:

    HashMapExample<String, String> example = new HashMapExample<String, String>();
    String importantField = (String)example.getImportantField();
    //set unimportant field
    example.put("Some random field", "some random value");
    String unimportantField = example.get("Some random field");

Based purely on the example you’ve given, I would suggest just using generics:

class EntityClass<T> {
  String commonParam1;
  String commonParam2;

  T typeParam1;
  T typeParam2;
}

The usage of it then becomes:

// ...

EntityClass<TypeA> typeAObject = new EntityClass<TypeA>();
EntityClass<TypeB> typeBObject = new EntityClass<TypeB>();

TypeA value1 = typeAObject.typeParam1;
TypeB valueB = typeBObject.typeParam1;

// ...

However as mentioned in the comments, depending on how you are using the entities, you may need to re-think the design.

LEAVE A COMMENT