0

The question is only relevant for typed programming languages, dynamic solutions aren't satisfying. Let's assume that the language is C++.

Example architecture:

- DisplayObject (base class)
-- Container (derived from DisplayObject)
-- Sprite (derived from DisplayObject)

So I have a game engine in my hands and it only has X and Y coordinates. Let's say I want to add a Z coordinate. To do this, I'd have to modify the base class DisplayObject. Because if I simply derive from it to add the Z-axis functionality, it would make it impossible to use classes Container and Sprite in my code without casting them to my new DisplayObject.

The question is, how to solve this without using casting?
There are dozens of classes derived from DisplayObject, so modifying them all one by one would look very weird.
I was also suggested delegation, but I don't see how to apply it here.

  • For this particular scenario, your best option is to modify DisplayObject to add the needed coordinate. – Robert Harvey Dec 30 '16 at 15:25
1

If the Z-axis functionality needs to be supported by all classes derived from DisplayObject, or if the functionality needs to be exposed in the interface of the base class, then your only effective option is to modify the DisplayObject class itself.

If the Z-axis functionality is only relevant for a subset of the derived classes, you can create a new class DisplayObject3D and change your inheritance tree to let the classes that need the Z-axis derive from DisplayObject3D. For example:

- DisplayObject (base class)
-- Container (derived from DisplayObject; doesn't need Z-axis)
-- DisplayObject3D (derived from DisplayObject)
--- Sprite (derived from DisplayObject3D)

In both cases, you are making such a fundamental change that you need to review all derived classes to see how the Z-axis functionality affects them. And possibly make changes to a number of them.

0

Adding third dimension to the base class with Z defaulting to 0 would fix your problem without breaking anything. However that's only case specific and in non-trivial example it might be much harder to re-implement existing class without wrecking havoc in your project. Also, consider that classes that don't require third dimension now would contain unused member Z, which smells like a code smell.

In my opinion problem lies in the fact, that DisplayObject wasn't from the get-go designed as such:

template <class DisplayObjectImpl>
class DisplayObject
{

  DisplayObject()
  : impl(new DisplayObjectImpl)
  {}

  virtual void render()
  {
    impl -> render
  }

  DisplayObject * impl;
}

class DisplayObject2D : public DisplayObject<DisplayObject2D>
{
  void render()
  {
    // some specific implementation of render
  }
}

class DisplayObject3D : public DisplayObject<DisplayObject3D>
{
  void render()
  {
    // some specific implementation of render
  }
}

or:

class DisplayObject
{
  static DisplayObject getDisplayObject2D()
  {
    DisplayObject object;
    impl = new DisplayObject2D;
    return object;
  }
  static DisplayObject getDisplayObject3D()
  {
    DisplayObject object;
    impl = new DisplayObject3D;
    return object;
  }
  virtual void render()
  {
    impl -> render
  }

  DisplayObject * impl;
}

class DisplayObject2D : public DisplayObject
{
  void render()
  {
    // some specific implementation of render
  }
}

class DisplayObject3D : public DisplayObject
{
  void render()
  {
    // some specific implementation of render
  }
}

As I see it you can either resort to hacking existing class with unsatisfying results (simply add z) or fix the root of the problem (redefine it akin to one of the above solutions) and probably waste a lot of time on nothing productive (unless you're planning to support 4-dimensional and 5-dimensional rendering in the future ;) )

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.