By paddloPayday loans

Home > Principles > Design Pattern Principles for ActionScript 3.0: Favor Object Composition Over Class Inheritance

Design Pattern Principles for ActionScript 3.0: Favor Object Composition Over Class Inheritance

bucketruleAfter getting slightly comfortable with the first dictum of design patterns, program to an interface; not an implementation, you may find this next one will knock the support blocks right from under you. In being advised to program to an interface, we get the idea that we type our objects to a superclass (abstract class or interface) and then we actually instantiate the object to a concrete class that is derived from the superclass. Doing so optimizes flexibility and minimizes dependency on implementations.

We assume that we are dealing with some kind of inheritance. It doesn’t matter if the inheritance is from an abstract class or pure interface. However, this next principle,

Favor object composition over class inheritance

looks like if we have a choice, we should avoid inheritance altogether. (We doan need no stinkin’ inheritance!)

Focus Here! A Little Inheritance Goes a Long Way

Instead of reassuring you that inheritance is really OK, you need to think of this new dictim as cautioning you to limit inheritance. With very few exceptions, when you use inheritance, you’re really only subclassing a few classes. Further, you want to subclass from abstract classes or implement from interfaces, and in either case, you don’t want to create some dodgy application that looks like your family tree. Each class should be focused on one task and encapsulated.

If you have the GoF book, take a close look, and you’ll see no more than three or four subclasses for any of the base classes in the examples. For instance, on page 50, you will see a very big inheritance class diagram. The base class is a Glyph interface, and it has three implementations. However, those implementations are not concrete classes. They’re abstract classes, each with three subclasses. Yes, the diagram does suggest you can add more, but that cannot be interpreted as suggesting that you should have more. Instead, think,

You shouldn’t have any more subclasses than you have siblings plus 1.

If you’re from a big family, this doesn’t work out too well, but it’s easy to remember. The key rule is that you want to maintain encapsulation by avoiding inheritance except from abstract classes or interfaces.

This can easily get to the point where you wonder why bother with inheritance at all? Other than the interface, the flexibility and direction it provides, abstract classes really don’t have a great deal to offer except a way to help insure incapsulation and perhaps a method or two that do not require overriding. (The Template Method Design Pattern [Chapter 9 in our book] is probably the best use of inheritance where you expect a good deal from the abstract parent class.)

So let’s imagine a slightly different place; one where you have little groups of classes connected to a common interface. If we try to build an application we find that we need some way to get from one archipeligo of classes to another to do anything useful.

Farming Out Requests

In this age of specialization and optimizing resource use, understanding what the Gang of Four means by favoring composition is pretty clear. Essentially, it’s saying that instead of trying to make everything using a single class or even interface, use the different existing classes to compose solutions. This point is covered on pp. 49-57 of our book, and I will not try your patience by reiterating it here. Rather, let me direct you to Figure 1-8 on page 57 where you can see how the processes of inheritance, delegation and instantiation all work together. (Also, take a look at our blog post on instantiation, inheritance and delegation.) Alternatively, go over the material on page 20 of GoF—after about 250 reads, it’s clear as a bell.

I’ve got to admit that when I’ve been in a hurry, I’ll put some giant hack of a class together, but I also know that when I do that, it’s the last time I’ll ever use that class. (Actually, I flatter myself by referring to such blobs as classes.) However, I’ve begun to think,

Hack = Death

and can effectively scare myself from doing that. Now I think,

One solution at a time.

So, instead of staggering to a task, I find it very easy to write an interface with just what I need and then implement it with the needed concrete classes. This process is made easier by Flex builder’s option of allowing you to pick the superclass of a class when creating the class file. If you use Flash, copy and paste works pretty well too. (I am most grateful to the recovering alcoholics among our readers who have pointed out the one-day-at-a-time method for writing design patterns.)

After assuaging my conscience by creating my interface and subclasses to get something done, I come to some point where I realize that I want to add functionality. Figure 1 shows how functionality can be (or must be in some cases) added when using inheritance as the primary building block of a project.
extending
Figure 1: Adding Functionality in an inheritance hierarchy

If you want to add functionality, all you have to do is to either override a method and add the new functionality, or if you need a current set of methods, add a new method as shown in Figure 1. Of course you can always add a new class, but whether you can do anything unique with it depends of the flexibility of your superclass. That’s not too bad, but you know this will not end well. As you add more functionality, your design becomes both cumbersome and susceptible to failure, as shown in Figure 2.
mess
Figure 2: The more you rely on inheritance alone, the more susceptible to error your program becomes as you add functionality

Before you know it, your program looks more incestuous than the House of Hapsburg. The more functionality you add, the greater the possibility of failure and the less clarity. If you’re very careful, you can still get it working right, but you might was well just plop all of your code in the Client and be done with it if you’re going to try and tip-toe your way through an inheritance minefield. Pretty soon, you look like the guy in Figure 3.
scream1
Figure 3: Programmer who tried to write it all using inheritance

Because clarity and re-use are essential to good OOP, we definitely want to avoid confusion and single-use code.

Alternative to Pure Inheritance

One of the ironies of the principle, favor composition over inheritance, is that most of the building blocks that make up a composed program are made up of components using inheritance. Figure 4 shows a class diagram illustrating where composition is favored over inheritance—even though all of the components use inheritance.
composition
Figure 4: Favoring Composition

As you can see in Figure 4, favoring composition does not mean abandoning inheritance. The functionality of the program is centered in the components, each with concrete classes joined by a common interface. Instead of adding functionality to each component by adding more classes or methods, functionality is accessed through references to a component that has the desired functionality—in other words through delegation.

Composition Made Easy

You may be thinking,

That’s exactly why I don’t use these darned things at work! I’d spend all my time trying work out how to link the functionality between components! It’s just a waste of Red Bull! Sheeeze!

The Gang of Four recognized this dodgy state of affairs when using delegation, and note,

Delegation works best when used in highly stylized ways—that is in standard patterns. (GoF, 21)

So instead of starting in a design desert and trying to work out a composition-based OOP design, GoF recommends using one of the many patterns that use delegation. Included in these patterns are the State (Chapter 10 our book), Strategy (Chapter 11 our book) and the Visitor. In fact, these three patterns depend on composition. Lots of other design patterns use delegation as well, and both MVC and PureMVC are models of delegation in designs. (Also, take at look at different kinds of delegation here.)

If there’s a Swiss Army knife design pattern, it’s the Strategy pattern, and that’s a good place to start. The State pattern is a close second, and something about state machines is just plain cool; so it too should be studied to better understand composition. Keep in mind that GoF considers delegation an extreme form of object composition. Nevertheless, they also consider it to be a better choice than class inheritance because it is the only way to provide a structure that is as powerful as inheritance without the accompanying problems of inheritance. And finally remember that you can use composition and inheritance together in a framework. They are not mutually exclusive as Figure 4 clearly shows.

Composition Lunch Bucket Rule

The second principle espoused by GoF is pretty clear—favor composition over inheritance. For something to put into your lunch bucket and take to work, though, we need something a bit more specific. First off, Mickey Mouse and most other cartoon characters only have three fingers and a thumb. Like the following:
cartoon

This will come in handy when remembering this second design pattern principle. To wit:

If you have more subclasses for a single base class than Mickey has fingers, delegate your next function.

Just look at your fingers and remember Mickey and most of his friends have one less finger than you—your fingers minus 1. (Naturally, if you have more or fewer fingers than the standard, you’ll need to make adjustments.)

Share
Categories: Principles
  1. February 21, 2009 at 1:50 pm | #1

    Hi,

    i like the article. In the end, i think you’re not really proposing to NOT to use inheritance, but simply to avoid using deep inheritance hierarchies, which i totally agree with. You giving arguments for composition in favor of inheritance, but i would also like to see arguments for using inheritance and when it makes sense.

    For example, building abstraction with types and subtypes is clearly something, you’ll want to use inheritance for. As Barbara Liskov stated, you should favor type inheritance over implementation inheritance and i think that nails it. If you want to make clear, that a specific type is related to a more general type, then inheritance is the way to go. If you are simply seeking for reusing as much code as possible, composition will be more suitable in many situations.

    One last word to encapsulation within inheritance hierarchies. I would like to say, that inheritance does not automatically mean strong coupling. You can achieve quite some loose coupling between a super- and a subclass, if you use protected and private wisely as well as final. In that sense i see inheritance simply as another kind of association between two classes. You will always want to control visibility and encapsulation between classes and you should do so within inherited classes, too.

  2. February 22, 2009 at 5:00 am | #2

    Hi Sven,

    When I write a post about a principle you can assume that it is not my principle but rather one from OOP or design patterns. I agree with the principles, but I am certainly not their author. Most are from GoF but you will find others from different sources, such as Barbara Liskov. So when readers say to me, …your principles… or …you are saying… I feel uneasy. I’m not claiming to be just the messenger because I fully support these principles. Rather, I am hoping readers of this blog will think about these principles in terms of the very smart people who developed them and not some wild hair I concocted.

    As you saw reading the entire post, the Gang of Four do not rule out using inheritance. Rather, they say that when you’re writing a program–and they’re thinking of big programs, not a simple gotoAndStop() one—you should think about it in terms of composition and not a hierarchy. Further, as you noted, the message is to keep the hierarchies shallow and the base classes abstract.

    One of the best examples of where you can clearly see composition at work with inheritance is the Abstract Factory Pattern. There you will see all these little hierarchies with the Client holding a reference to abstract classes and composing a solution rather than relying on a single hierarchy. Thus, you have both programming to an interface instead of an implementation and and favoring composition over inheritance.

    I’d like to agree with you and say if you’re really careful with hierarchies using private, protected and final access statements that everything will be dandy. I cannot say that. Rather, I’m saying we (not you, but we) need to evaluate how we use inheritance in our programs, and scale them back. Instead of adding another class or method, we need to consider adding another component to the framework to handle an added functionally.

    When we do use hierarchies we need to consider design patterns that make use of them and examine exactly what’s going on. One of my favorite design patterns is the Template Method (Chapter 9 in our book). Your query is addressed in the section “Why Inheritance and Not Composition?” on page 335. It points out that there are indeed situations where inheritance is the way to go; so neither GoF nor we are dogmatic about inheritance.

    However, let me hark back to the original point, favor composition over class inheritance. For the most part, it does say, don’t depend on inheritance to solve your programming problems. If you do, you’re likely to run into dependency problems, broken encapsulation, and a whole host of other problems.

    Like everyone else who’s been programming for over 30 years, I like to think I know what I’m doing, but the fact of the matter is that I’ve had more time to build up some pretty bad habits. As programming languages change and evolve, as ActionScript 3.0 has, I need to re-think everything, and I have found that design patterns provide a way to kick me out of some of these habits. Favoring composition over class inheritance is a good habit I want to adopt, and it means that deep hierarchies need to be dumped.

    Kindest regards,
    Bill

  3. February 23, 2009 at 1:56 am | #3

    Hi Bill,

    agreed. I see, we’re on the same track. I guess, what i wanted to express was, by explaining the specific scenarios, in which inheritance makes sense (as you seem to have done in you book, sorry haven’t read it yet, will do so asap) and presenting those in contrast to the scenarios, in which it doesn’t make sense and principles like composition are more suitable, developers might understand the pros and cons better and will more likely choose it more wisely.

    And to your first paragraph: I am aware, that you are quoting other people in your posts. But it would be boring, to simply read quotes on this blog. So what makes reading this blog interesting, is the combination of those quotes and your very own experience and the way, you look on those things. Otherwise, i could simply buy the book from the GoF (if i hadn’t already done so). So, go on, take the risk of expressing things in your own words, i’m sure, that’s what keeps people reading your stuff.

  4. February 23, 2009 at 3:20 am | #4

    Hi Sven,

    Thanks for those kind words. I think that the most important discovery I made in this blog is that I’m in the same boat as everyone else as far as immersing myself in good OOP. (Sounds like being dipped in a tasty pudding.) That is, I know about the principles, but too often I’ll just put something together and worry about structure later. If things are really hectic, later never comes… Unfortunately, especially with smaller projects, everything works pretty well, and that’s why bad habits (mine!) are so hard to break. I almost wish that any program I wrote NOT following good OOP would explode like a big bomb, singe my eyebrows, set my hair on fire and make the dog howl. Then the bad habits would be easy to break.

    Lacking such a handy reminder as exploding programs, I set about to put all of the main DP and OOP principles in one place and in the form of good habits (this and the previous two posts on principles) and ways to help remind us what the principles mean–The Lunch Bucket Rules.

    Like all principles, rules or guidelines, the first step is getting them all down pat. Once they become part of a mindset, then you can begin to find exceptions. Right now, though, I’m trying to get them into a format where I can put them into an AIR application and have it handy. (See http://nemo.mwd.hartford.edu/~wsanders/lunchDP/ for the starting point–ideas welcomed!)

    Thank you again for your insights,
    Bill

  5. drew
    March 1, 2009 at 8:35 pm | #5

    Hi,

    For me it is really difficult to be observant of the right design especially if you are tied to short schedules. As a result I sometime find myself hoping that I could rewrite/redesign everything again though sadly there are always not enough time to recode.

  6. March 2, 2009 at 3:02 am | #6

    Hi Drew,

    I think that you’ve expressed what a lot of developers experience concerning OOP and design patterns. It reminds me of the 17th Century poet Andrew Marvell’s poem, To his Coy Mistress

    Had we but world enough, and time,
    This coyness, lady, were no crime.

    For, lady, you deserve this state,
    Nor would I love at lower rate.

    But at my back I always hear
    Time’s winged chariot hurrying near;….

    As all 17th Century literary scholars know, Marvell was really a Fortran I programmer (and did comic books on the side) and his coy mistress was a gig he had to get done yesterday!

    Ask yourself this:

    Is there just one thing demonstrating good OOP or Design Patterns that I can do with this project?

    Now that you have the handy Lunch Bucket Rules this shouldn’t be as much of a problem as before. Nobody, and I mean nobody is able to follow all of the OOP and design pattern rules all the time. However, being realistic, we need to start somewhere. Over time as we develop modules done using design patterns, we become more accustomed to doing it right. Let’s face it, at some point we gave up sequential programming in favor of procedural programming, but it didn’t happen all at once. Then, we gave up procedural programming for object oriented programming (OOP) and then started design patterns, and it’s not going to happen all at once either. However, if we don’t start someplace, it will never happen.

    Take care,
    Bill

  1. February 25, 2009 at 4:38 am | #1
  2. April 14, 2009 at 7:19 pm | #2

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>