1

I'm programming in C#. My class designs are getting rather complex. In many situations I'm attempting to avoid inheritance when possible; e.g., I prefer "has-a" design instead of "is-a" design.

I believe that my designs will run into a situation where the indicated eventual design would be multiple inheritance. I'm aware of the no-no's of multiple inheritance, and that both Java and C# don't allow that.

I will try and write some pseudo code to illustrate my situation.

Let's say in my application in development, I want to make a distinction between items that are visible on screen, and items that aren't. I will make a class "DisplayObject" that is the root class of all items to be displayed.

I have a "Button" class that will then inherit from DisplayObject.

class Button : DisplayObject

However, I want to create an abstract class "Clickable". (I know that, at this point, some may say "use an interface" e.g., IClickable. But for now, set that suggestion aside.)

The point of Clickable, and that being an abstract class, is that I want to provide some default functionality. The Button class (obviously) cannot inherit from both DisplayObject and Clickable.

One idea might be to make Clickable inherit from DisplayObject, and then Button inherit from Clickable.

class Clickable : DisplayObject

class Button : Clickable

That seems like a good idea, since I want to create a Link class that is also clickable. "Link" class can inherit from Clickable.

Without detailing what sort of "stinky" code growth this might cause, I seem to be working towards some sort of usage of the Decorator pattern. But from what I remember, the Decorator pattern is implemented such:

class Button : ClickableDecorator<DisplayObject>

I don't like that either. Especially if I plan on having a lot of "Decorator" additions to my class definitions.

So I might then be inclined to try making a List of pseudo Decorators as a member of the Button class:

public List<Decorator> Decorators { get; set; }

But that can still get confusing.

To summarize (in hopes of finding a solution):

  1. I don't want to do much "Prefactoring" (refactoring done ahead of time that is actually counterproductive).
  2. I don't want to go with a simplistic recommended solution, as that will cause a lot of headaches down the road, which will require a lot of Refactoring.
  3. Essentially, I'm hoping that there is a "has-a" solution to a multiple "is-a" dilemma.

Thank you for reading this far!

Chris
  • 21
  • 2

1 Answers1

1

I good way to know if your code smells is to take a sniff. If you think it smells, then there's a very good chance that everyone else with a half-working nose thinks it smells too.

It sounds to me like you're smelling something, and it aint good.. You could try and hide the smell and make excuses to others as to what the lingering odour is, or you could start to work on the core of the problem which (imho) is represented by, among other things, this comment:

However, I want to create an abstract class "Clickable". (I know that, at this point, some may say "use an interface" e.g., IClickable. But for now, set that suggestion aside.)

Why lay it aside? It's a perfectly valid thought to consider (I'm not saying do it, I am saying consider it).

As this answer describes, interfaces are about describing can-do, inheritance describes is-a. So a Button that "is-a" DisplayObject and "can-do" Click() is one way of thinking about it which perhaps you should consider.

class Button : DisplayObject, IClickable

This is handy because it allows you to, for example add buttons and other clickables to a List<IClickable> for iteration, or design a handler that takes anything that implements IClickable.

Another way to think about it is using multiple layers of inheritance:

class ClickableDisplayObject : DisplayObject { ... }

class Button : ClickableDisplayObject { ... }

Everything displayable doesn't have to derive directly from DisplayObject.

It's hard to give you any more advice without knowing what specific problems you are trying to solve, but in closing I'd say:

  1. If you're worried about so-called prefactoring, and you don't want too much refactoring then take a good hard look at why you've made the decisions you've made so far, and consider that perhaps there's a reason that most of the C# world doesn't struggle with your exact question, in spite of billions of lines of code over the years. If you think you need multiple inheritance, you're thinking about it wrong.
  2. Forget has-a for now. You mention it at the top and again at the bottom, but I haven't seen a good explanation for how it is actually a problem, and why inheritance and interfaces can't solve it for you in a nice, clean way.
  3. There will be a clean (enough) way to do it without multiple inheritance, but only if you're willing to follow good coding principles such as SOLID, particularly the "S" part. It might mean more boilerplate code, more source files, more classes, or some other spurious concern, but it will be infinitely more maintainable, reusable, testable and you'll soon notice somewhere along the way that the original smell has simply disappeared...
pcdev
  • 2,852
  • 2
  • 23
  • 39
  • I'll review the links provided. the main reason I wanted to avoid using interfaces is because I don't want to have to duplicate code; i.e., I plan on using abstract classes where a minimum amount of functionality is defined. and I think some approach of the composite design pattern will be useful. – Chris Mar 03 '18 at 01:34