[language-agnostic] Prefer composition over inheritance?



14 Answers

Think of containment as a has a relationship. A car "has an" engine, a person "has a" name, etc.

Think of inheritance as an is a relationship. A car "is a" vehicle, a person "is a" mammal, etc.

I take no credit for this approach. I took it straight from the Second Edition of Code Complete by Steve McConnell, Section 6.3.

Question

Why prefer composition over inheritance? What trade-offs are there for each approach? When should you choose inheritance over composition?




With all the undeniable benefits provided by inheritance, here's some of its disadvantages.

Disadvantages of Inheritance:

  1. You can't change the implementation inherited from super classes at runtime (obviously because inheritance is defined at compile time).
  2. Inheritance exposes a subclass to details of its parent's class implementation, that's why it's often said that inheritance breaks encapsulation (in a sense that you really need to focus on interfaces only not implementation, so reusing by sub classing is not always preferred).
  3. The tight coupling provided by inheritance makes the implementation of a subclass very bound up with the implementation of a super class that any change in the parent implementation will force the sub class to change.
  4. Excessive reusing by sub-classing can make the inheritance stack very deep and very confusing too.

On the other hand Object composition is defined at runtime through objects acquiring references to other objects. In such a case these objects will never be able to reach each-other's protected data (no encapsulation break) and will be forced to respect each other's interface. And in this case also, implementation dependencies will be a lot less than in case of inheritance.




Aside from is a/has a considerations, one must also consider the "depth" of inheritance your object has to go through. Anything beyond five or six levels of inheritance deep might cause unexpected casting and boxing/unboxing problems, and in those cases it might be wise to compose your object instead.




Inheritance is a very powerfull machanism for code reuse. But needs to be used properly. I would say that inheritance is used correctly if the subclass is also a subtype of the parent class. As mentioned above, the Liskov Substitution Principle is the key point here.

Subclass is not the same as subtype. You might create subclasses that are not subtypes (and this is when you should use composition). To understand what a subtype is, lets start giving an explanation of what a type is.

When we say that the number 5 is of type integer, we are stating that 5 belongs to a set of possible values (as an example, see the possible values for the Java primitive types). We are also stating that there is a valid set of methods I can perform on the value like addition and subtraction. And finally we are stating that there are a set of properties that are always satisfied, for example, if I add the values 3 and 5, I will get 8 as a result.

To give another example, think about the abstract data types, Set of integers and List of integers, the values they can hold are restricted to integers. They both support a set of methods, like add(newValue) and size(). And they both have different properties (class invariant), Sets does not allow duplicates while List does allow duplicates (of course there are other properties that they both satisfy).

Subtype is also a type, which has a relation to another type, called parent type (or supertype). The subtype must satisfy the features (values, methods and properties) of the parent type. The relation means that in any context where the supertype is expected, it can be substitutable by a subtype, without affecting the behaviour of the execution. Let’s go to see some code to exemplify what I’m saying. Suppose I write a List of integers (in some sort of pseudo language):

class List {
  data = new Array();

  Integer size() {
    return data.length;
  }

  add(Integer anInteger) {
    data[data.length] = anInteger;
  }
}

Then, I write the Set of integers as a subclass of the List of integers:

class Set, inheriting from: List {
  add(Integer anInteger) {
     if (data.notContains(anInteger)) {
       super.add(anInteger);
     }
  }
}

Our Set of integers class is a subclass of List of Integers, but is not a subtype, due to it is not satisfying all the features of the List class. The values, and the signature of the methods are satisfied but the properties are not. The behaviour of the add(Integer) method has been clearly changed, not preserving the properties of the parent type. Think from the point of view of the client of your classes. They might receive a Set of integers where a List of integers is expected. The client might want to add a value and get that value added to the List even if that value already exist in the List. But her wont get that behaviour if the value exists. A big suprise for her!

This is a classic example of an improper use of inheritance. Use composition in this case.

(a fragment from: use inheritance properly).




Inheritance is very powerful, but you can't force it (see: the circle-ellipse problem). If you really can't be completely sure of a true "is-a" subtype relationship, then it's best to go with composition.




While in short words I would agree with "Prefer composition over inheritance", very often for me it sounds like "prefer potatoes over coca-cola". There are places for inheritance and places for composition. You need to understand difference, then this question will disappear. What it really means for me is "if you are going to use inheritance - think again, chances are you need composition".

You should prefer potatoes over coca cola when you want to eat, and coca cola over potatoes when you want to drink.

Creating a subclass should mean more than just a convenient way to call superclass methods. You should use inheritance when subclass "is-a" super class both structurally and functionally, when it can be used as superclass and you are going to use that. If it is not the case - it is not inheritance, but something else. Composition is when your objects consists of another, or has some relationship to them.

So for me it looks like if someone does not know if he needs inheritance or composition, the real problem is that he does not know if he want to drink or to eat. Think about your problem domain more, understand it better.




In Java or C#, an object cannot change its type once it has been instantiated.

So, if your object need to appear as a different object or behave differently depending on an object state or conditions, then use Composition: Refer to State and Strategy Design Patterns.

If the object need to be of the same type, then use Inheritance or implement interfaces.




Even though Composition is preferred, I would like to highlight pros of Inheritance and cons of Composition.

Pros of Inheritance:

  1. It establishes a logical "IS A" relation. If Car and Truck are two types of Vehicle ( base class), child class IS A base class.

    i.e.

    Car is a Vehicle

    Truck is a Vehicle

  2. With inheritance, you can define/modify/extend a capability

    1. Base class provides no implementation and sub-class has to override complete method (abstract) => You can implement a contract
    2. Base class provides default implementation and sub-class can change the behaviour => You can re-define contract
    3. Sub-class adds extension to base class implementation by calling super.methodName() as first statement => You can extend a contract
    4. Base class defines structure of the algorithm and sub-class will override a part of algorithm => You can implement Template_method without change in base class skeleton

Cons of Composition:

  1. In inheritance, subclass can directly invoke base class method even though it's not implementing base class method because of IS A relation. If you use composition, you have to add methods in container class to expose contained class API

e.g. If Car contains Vehicle and if you have to get price of the Car, which has been defined in Vehicle, your code will be like this

class Vehicle{
     protected double getPrice(){
          // return price
     }
} 

class Car{
     Vehicle vehicle;
     protected double getPrice(){
          return vehicle.getPrice();
     }
} 






"Prefer composition over inheritance" is a design principle, which says don't abuse inheritance when it doesn't fit.

If no real world hierarchical relationship exists between two entities, don't use inheritance, but instead use composition. Composition represents "HAS A" relationship.

E.g. Car HAS A Wheels, body, engine, etc. But if you inheritance here, it becomes CAR IS A Wheel - which is incorrect.

For further explanations, refer to prefer composition over inheritance




I agree with @Pavel, when he says, there are places for composition and there are places for inheritance.

I think inheritance should be used if your answer is an affirmative to any of these questions.

  • Is your class part of a structure that benefits from polymorphism ? For example, if you had a Shape class, which declares a method called draw(), then we clearly need Circle and Square classes to be subclasses of Shape, so that their client classes would depend on Shape and not on specific subclasses.
  • Does your class need to re-use any high level interactions defined in another class ? The template method design pattern would be impossible to implement without inheritance. I believe all extensible frameworks use this pattern.

However, if your intention is purely that of code re-use, then composition most likely is a better design choice.




When you want to "copy"/Expose the base class' API, you use inheritance. When you only want to "copy" functionality, use delegation.

One example of this: You want to create a Stack out of a List. Stack only has pop, push and peek. You shouldn't use inheritance given that you don't want push_back, push_front, removeAt, et al.-kind of functionality in a Stack.




When you have an is-a relation between two classes (example dog is a canine), you go for inheritance.

On the other hand when you have has-a or some adjective relationship between two classes (student has courses) or (teacher studies courses), you chose composition.




Didn't find a satisfactory answer here, so I wrote a new one.

To understand why "prefer composition over inheritance", we need first get back the assumption omitted in this shortened idiom.

There are two benefits of inheritance: subtyping and subclassing

  1. Subtyping means conforming to a type (interface) signature, i.e. a set of APIs, and one can override part of the signature to achieve subtyping polymorphism.

  2. Subclassing means implicit reuse of method implementations.

With the two benefits comes two different purposes for doing inheritance: subtyping oriented and code reuse oriented.

If code reuse is the sole purpose, subclassing may give one more than what he needs, i.e. some public methods of the parent class don't make much sense for the child class. In this case, instead of favoring composition over inheritance, composition is demanded. This is also where the "is-a" vs. "has-a" notion comes from.

So only when subtyping is purposed, i.e. to use the new class later in a polymorphic manner, do we face the problem of choosing inheritance or composition. This is the assumption that gets omitted in the shortened idiom under discussion.

To subtype is to conform to a type signature, this means composition has always to expose no less amount of APIs of the type. Now the trade offs kick in:

  1. Inheritance provides straightforward code reuse if not overridden, while composition has to re-code every API, even if it's just a simple job of delegation.

  2. Inheritance provides straightforward open recursion via the internal polymorphic site this, i.e. invoking overriding method (or even type) in another member function, either public or private (though discouraged). Open recursion can be simulated via composition, but it requires extra effort and may not always viable(?). This answer to a duplicated question talks something similar.

  3. Inheritance exposes protected members. This breaks encapsulation of the parent class, and if used by subclass, another dependency between the child and its parent is introduced.

  4. Composition has the befit of inversion of control, and its dependency can be injected dynamically, as is shown in decorator pattern and proxy pattern.

  5. Composition has the benefit of combinator-oriented programming, i.e. working in a way like the composite pattern.

  6. Composition immediately follows programming to an interface.

  7. Composition has the benefit of easy multiple inheritance.

With the above trade offs in mind, we hence prefer composition over inheritance. Yet for tightly related classes, i.e. when implicit code reuse really make benefits, or the magic power of open recursion is desired, inheritance shall be the choice.




To address this question from a different perspective for newer programmers:

Inheritance is often taught early when we learn object-oriented programming, so it's seen as an easy solution to a common problem.

I have three classes that all need some common functionality. So if I write a base class and have them all inherit from it, then they will all have that functionality and I'll only need to maintain it in once place.

It sounds great, but in practice it almost never, ever works, for one of several reasons:

  • We discover that there are some other functions that we want our classes to have. If the way that we add functionality to classes is through inheritance, we have to decide - do we add it to the existing base class, even though not every class that inherits from it needs that functionality? Do we create another base class? But what about classes that already inherit from the other base class?
  • We discover that for just one of the classes that inherits from our base class we want the base class to behave a little differently. So now we go back and tinker with our base class, maybe adding some virtual methods, or even worse, some code that says, "If I'm inherited type A, do this, but if I'm inherited type B, do that." That's bad for lots of reasons. One is that every time we change the base class, we're effectively changing every inherited class. So we're really changing class A, B, C, and D because we need a slightly different behavior in class A. As careful as we think we are, we might break one of those classes for reasons that have nothing to do with those classes.
  • We might know why we decided to make all of these classes inherit from each other, but it might not (probably won't) make sense to someone else who has to maintain our code. We might force them into a difficult choice - do I do something really ugly and messy to make the change I need (see the previous bullet point) or do I just rewrite a bunch of this.

In the end, we tie our code in some difficult knots and get no benefit whatsoever from it except that we get to say, "Cool, I learned about inheritance and now I used it." That's not meant to be condescending because we've all done it. But we all did it because no one told us not to.

As soon as someone explained "favor composition over inheritance" to me, I thought back over every time I tried to share functionality between classes using inheritance and realized that most of the time it didn't really work well.

The antidote is the Single Responsibility Principle. Think of it as a constraint. My class must do one thing. I must be able to give my class a name that somehow describes that one thing it does. (There are exceptions to everything, but absolute rules are sometimes better when we're learning.) It follows that I cannot write a base class called ObjectBaseThatContainsVariousFunctionsNeededByDifferentClasses. Whatever distinct functionality I need must be in its own class, and then other classes that need that functionality can depend on that class, not inherit from it.

At the risk of oversimplifying, that's composition - composing multiple classes to work together. And once we form that habit we find that it's much more flexible, maintainable, and testable than using inheritance.




Related