Suppose I want to make a custom button from scratch:
- BasicButton : NSObject
So I created a class which knows how to handle mouse events and forward messages to interested receivers when the button is clicked (via delegation, target/action, notifications, whatever). - SolidColorButton : BasicButton : NSObject
My button now works but it’s invisible, so I decided to draw a solid background to bring the button to life (not very good in terms of UI design but let’s pretend). - LabelledButton : SolidColorButton : BasicButton : NSObject
Now let’s say I want to add a label on the button, so I’ve created a another subclass that can draw text on the button.
So now I have a button which can handle mouse events, draws a solid background, and draws some text. But what happens now if I decide I need a button with an image for a background instead of the solid color, but that still knows how to draw a label? This is where the single-inheritance subclassing approach fails. I can’t combine the mouse handling, label drawing and image drawing at will, I can only choose a level of refinement down the inheritance chain.
So I guess my question is: What’s the way to implement these separate modules so that they can then be mixed and matched to create some sort of offspring object which has the combined features of the desired modules and nothing else?
Example, I’d want to be able to write modules like:
- Mouse handling
- Keyboard handling
- Solid background
- Image background
- Label
- etc.
and then have the ability to to make a specific button which: a) handles mouse, b) draws a background and c) has a label; and nothing else.
The question is specific to how one would do this in Objective-C or another single-inheritance OOP language. In Ruby a way to do this would be using mixins.
You already noticed that inheritance is a bad idea here. The Decorator Pattern would come in handy: you will have one button class and several decorators that “decorate” the button (wrap it and add functionality) and can be combined arbitrarily.
Class diagram:
Object diagram (for your example):