9

Whether an object physically exists or not, we can choose to model it in different ways. We could arbitarily use generalisation or composition in many cases. However, the GoF principle of "favour composition over generalisation [sic]" guides us to use composition. So, when we model, for example, a line then we create a class that contains two members PointA and PointB of the type Point (composition) instead of extending Point (generalisation). This is just a simplified example of how we can arbitarily choose composition or inheritance to model, despite that objects are usually much more complex.

How do we know that this is the right choice? It matters at least because there could be a ton of refactoring to do if it is wrong?

17

It's not always the right choice. It is the favourable one in most cases. When a composite model requires change or extension, it is considerably more resistant to that because you can change the composition without fear of affecting other classes inadvertently.

How do we know this? From experience, and the experience of others.

I have seen many situations where a massive class hierarchy has grown out of what started as a simple concept, and this is where your major refactoring becomes necessary. Meanwhile I have never seen a situation where a composition structure needed refactoring into inheritance.

But my anecdotal evidence should not be enough. Just look around the internet and a good number of people have had the same experiences.

  • I'm liking it; take an upvote. – CarneyCode Apr 10 '11 at 12:39
  • +1 for "I have never seen a situation where a composition structure needed refactoring into inheritance." – Kazark Nov 26 '12 at 17:34
7

If you want a stronger rule of thumb beyond "favor composition over inheritance" then I might suggest something like this :

Of the two ways to specialize an object - Inheritance and Composition - you should use inheritance only when you need your object to be polymorphic ( be substitutable ) for the base class you are specializing.

However like all rules of thumb, once you understand the rule - then you are free to break the rule :)

0

I don't see how composition and generalization are alternatives and failed to find the quote.
Composition and inheritance are (to achieve specialization), and it can be argued, that abstraction and generalization are (to achieve modularity).

What you want is your design to be simple and plausible, which are two qualities that inherently quite easily measured.
In your case, it seems more plausible to compose a line of two points instead of extending it, because you would naturally define a line by two points, rather than by extending the concept of a point.

  • Is it more natural? A line is no more two points than it is a single point extended? – CarneyCode Apr 10 '11 at 12:49
  • 2
    I've never seen a line definition that does not include the fact that it is made of 2+ points. Even using an equation of a line if you only have 1 x value in your domain of numbers then it is a point, not a line. – Rig Sep 20 '11 at 15:34
0

Favour happens when both candidate qualifies. The problem stated in the question fails on this account, because it only has a composition option.

"Composition could use generalization as well". Does this statement make sense to us? If not then we are not yet ready to grasp the 'favour' rule.

Why we are favouring Composition is that Composition offers more extension/flexiblity possiblities than generalization. This extension/flexiblity refers mostly to runtime/dynamic flexibility(which is achieved with the combination of interfaces and composition).

The benefit is not immediately visible. To see the benefit you need to wait for the next unexpected change request. So in most cases those sticked to generalization fails when compared to those who embraced composition(except one obvious case mentioned later). Hence the rule. From a learning point of view if you can implement a dependency injection successfully then you should know which one to favour and when. The rule helps you in making a decision when you are not sure which one to choose. Again you should be able to see both options in the first place to favour one.

Summary: Composition :The coupling is reduced by just having some smaller things you plug into something bigger, and the bigger object just calls the smaller object back. Generlization: From a 3rd party API point of view defining that a method can be overridden is a stronger commitment than defining that a method can be called (sure win for Generalization). And never forget that with composition you are using generalization too, from a interface instead of a big class. But the whole credit goes to composition unfortunately.

-4

Today I wrote about 300 LoC. And I cannot remember any principle that I could violate and did not violated. Refactoring will save my soul, I hope.

If abstraction is dictated by 3d party api - usually it is correct to use inheritance. In domestic design entity must be either abstract, or sealed. Abstract entity potentially must have about 3 inheritors. I do not like one-virtual-method extension points. All above is about my taste. I'm not speaking about interface abstraction, which is completle diffferent story.

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.