vendredi 27 mars 2020

Pattern for dealing with types with different interfaces in a collection

I'll start with what is it that I want to achieve. We have a graph DB that stores different types of nodes. Each type of nodes have a certain set of properties. Each property is a string in the DB, but can be an encoding of a more complicated data structure. For example, let's say we have:

PersonNode {
  name,
  age,
}

DogNode {
  breed,
  favorite_foods, // JSON-encoded list of strings
}

In our client code, we have a low-level Node class that exposes the properties of a node as a key-value map. We want to built upon this low-level Node to expose a type-safe interface to end users, so they don't have to check for key existence / decode things themselves.

A coworker proposed that we can create a different class for each type of nodes, with different getters for properties. For example (in pseudocode):

class PersonNode {
  string get_name() { ... }

  int get_age() { ... }
}

class DogNode {
  string get_breed() { ... }

  list<string> get_favorite_foods() { ... }
}

But my concern with this approach is that if we want to return different types of nodes from the DB, we need to store them in a collection, which means we need to make different node types inherit from a BaseNode. But then the user will need to do runtime type checks for each node before they can use their getters. I feel this defeats the purpose of polymorphism:

list<BaseNode> nodes = get_nodes_from_db()

for node in nodes:
  if instanceof(node, PersonNode):
    ...
  elif instanceof(node, DogNode):
    ...

Is there any pattern we can use that avoids runtime type checks, but can also give us type safety when accessing the properties of each node type?

Aucun commentaire:

Enregistrer un commentaire