1

Background

I'm creating a GUI that has graphs made of different node types and connections, as well as plots that can be made from the nodes.

My inheritance tree looks like this:

original inheritance tree

As you can see, all graph nodes and plots are moveable. Plots and some graph nodes are resizeable. Now, I want to let the user to be able to group together all the graph nodes, inside of another node type called a Network.

network inheritance tree

So I want to add a method called restrict to all non-Plot classes, despite the fact they have different base classes.

Question

One approach I've heard about is to use mixins, but they feel like overkill. Is there an easier way to add methods to classes that inherit from different base classes? How do I keep the principle "compositionality over inheritance" in mind in this case?

I don't think I should just add restrict to Component as this would create a useless method for Plots that would never be used and this feels like a bad code smell.

I understand I can use Interfaces for multiple inheritance, but Interfaces don't automatically use the reference implementation, so I'd have to copy a bunch of super calls into each method definitions. This feels like a lot of code duplication. Is there a way to automatically use the reference implementation from an Interface if no implementation is given by the implementing class?

Seanny123
  • 8,776
  • 13
  • 68
  • 124
  • Mixins may be overkill in your case, but it would give you the composition over inheritance you mentioned, as well as not having the super calls as you mentioned also. Typescript now supports mixins fully. I just got done implementing typescript mixins and they do work after getting past the initial setup hurdle. The mixins would give you the sort of inheritance you seem to need with the 'automatic' implementation. – Brandon Culley Aug 11 '17 at 18:03

1 Answers1

2

I'd like to post a comment asking for more information on your situation so I can better prepare an answer, but my reputation amount doesn't allow it (a chicken & egg scenario preventing me from constructing a better answer to have more reputation, to post comments...) so here's my best answer for now, which I may update.

Intuitively I think your problem & solution is very much a conceptual one, once you address the problem with the concept, the solution won't require any fancy coding.

If I had a better "real world" idea about what it is you're doing, I'm sure I could help come up with some code design to achieve it, but at the moment it's arbitrary "nodes" etc. For example, what is the nature of this "grouping" you're talking about?

Knowing nothing else, I have a few suggestions;

  • What are the implications of simply having PassthroughNode inherit from ResizableComponent? In some cases this might cause an object to take more resources than it needs, but if it doesn't add much, and provides the functionality you're after and is the simplest change to make, it's a viable option
  • You haven't mentioned "Interfaces" at all, which makes me think you're not aware of them, as it seems like exactly what you need here. Both Node and PassthroughNode implement a "Groupable" interface, and internally have their own implementations of how to make themselves "groupable".
  • And this may be crazy, but Component base class might implement the groupable behaviour instead, then any object can be groupable :)
Domarius
  • 413
  • 1
  • 3
  • 13
  • It's true that inheriting from "ResizableComponent" and then over-writing all the things that make it resizable is an option, but it doesn't feel like a good one. Interfaces seem to be whole "mixin" thing is accomplishing, but that still seems to require code duplication, because how do I define an external function as the implementation of both of the interfaces? I mention why I don't like the last scenario in the newest edit. – Seanny123 Aug 02 '17 at 01:57
  • 1
    Never heard of mixins to be honest. Interfaces are a more fundamental OOP concept. It's true that the interfaces merely define the stubs of available functions and the implementation is still required inside each class file. But your goal is to minimise code duplication, not eradicate it with zero tolerance. You'll use composition first, inheritance only when absolutely useful, and interfaces to make your objects flexible and cut down code duplication by having the same code re-use objects that use the same interface. – Domarius Aug 02 '17 at 04:58
  • 1
    I've learned through experience that you will kill yourself trying to avoid ANY and ALL code duplicating, spending hours upon hours re-designing and re-coding each time you encounter some similar code, just to have bragging rights that you saved 10 lines of code from being duplicated. When you've only duplicated code once, especially when it's not very much, in the big scheme of things is not so bad, if it keeps development progressing and the bigger gain is in having your objects be used by the same code due to interfaces, even though they may duplicate a bit of code internally. – Domarius Aug 02 '17 at 04:59
  • I've come to the same conclusion as you. I decided to go with interfaces and not to drive myself crazy trying to avoid code de-duplication in this case. Thank you for helping me navigate the OOP landscape. – Seanny123 Aug 02 '17 at 14:41
  • Happy to help others avoid the hours of frustration I've endured :) Just remember, you can always "optimise" or "tidy-up" later, and if you don't feel a compelling need to at any point later (eg. program not running slow, code maintenance not taking longer than it should), then it never really mattered! Paying too much attention to things that may not matter in the end is the bane of every programmer, something we all have to constantly try to avoid. – Domarius Aug 03 '17 at 02:24
  • By the way, your upvote got me the points I needed to be allowed to comment, thanks :) – Domarius Aug 03 '17 at 02:25