5

I am developing a visual editor for an entity component system. The editor must be able to modify the members of differents components subtypes, so we have a specific window for each component subtype. The problem is we can't modify the components to implement a polymorphic method to display the correct window since it's a extern library. So what would be a appropriate design to avoid this:

void edit(Component component) {
    if (component instanceOf Position) {
       new PositionEditorWindow((Position) component).display();
    } else if (component instanceOf Velocity) {
       new VelocityEditorWindow((Velocity) component).display();
    } else if ...
}

(Separate comment: if we can modify the components, does it makes any sense to add a polymorphic method with editor logic to a component? I was thinking a visitor has more sense)

4
  • Does this answer your question? How to tackle a 'branched' arrow head anti-pattern? – gnat Feb 4 at 10:39
  • 1
    If you can't modify or wrap the components then there's no particularly good solutions. Instanceof it is. If you can modify them, then the visitor pattern would likely be a good solution. – amon Feb 4 at 10:50
  • 2
    You're right that the visitor makes more sense, but I'd like to point out something else: Components are the central abstraction in ECS (everything depends on a robust set of components). It's not your components that need to be polymorphic, it's the editor views (within the view rendering abstraction). With ECS, there should already be a mechanism that lets you recognize component types, so you can use that as an input to a view-producing factory (create a different view for each component type), data-bind each view to the corresponding component, and just plug it into the GUI framework. – Filip Milovanović Feb 4 at 12:40
  • 1
    If you are already using a GUI framework of some sort (3rd party or homegrown), you likely already have some base class or an interface that can play the role of IComponent in Philip Kendall's answer (you don't necessarily have to introduce a new interface). Also, note that here, the usage pattern of one view for each component in the same entity is different from the typical ECS scenario where a system handles a bunch of components of the same type, so there is some justification to go outside of the usual ECS paradigm. – Filip Milovanović Feb 4 at 12:40
12

The problem is we can't modify the components to implement a polymorphic method to display the correct window since it's a extern library.

You may not be able to modify the component, but you can almost certainly compose them to produce the same effect. Pseudo code, adapt to your favourite language:

interface IComponent
{
  void display();
}

class PositionComponent : IComponent
{
  private Position _p;

  PositionComponent(Position p) { _p = p; }

  void display()
  {
    new PositionEditorWindow(_p).display();
  }
}

class VelocityComponent : IComponent
{
  private Velocity _v;

  VelocityComponent(Velocity v) { _v = v; }

  void display()
  {
    new VelocityEditorWindow(_v).display();
  }
}

and your edit function can now just call display on an IComponent.

This is of course an example of the facade pattern:

Provide a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use. This can be used to simplify a number of complicated object interactions into a single interface.

and yes, you absolutely can/should add more functionality to the facade to represent the other actions that components can perform.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.