Prefer composition over inheritance?
Asked Answered
B

36

1990

Why prefer composition instead of inheritance? What trade-offs are there for each approach? And the converse question: when should I choose inheritance instead of composition?

Bracket answered 8/9, 2008 at 1:58 Comment(3)
See also which class design is betterCeuta
in one sentence inheritance is public if you have a public method and you change it it changes the published api. if you have composition and the object composed has changed you don't have to change your published api.Malvasia
This is a good read on the topic: Medium.com: Composition vs. Inheritance: Pros and ConsLoewe
C
1447

Prefer composition over inheritance as it is more malleable / easy to modify later, but do not use a compose-always approach. With composition, it's easy to change behavior on the fly with Dependency Injection / Setters. Inheritance is more rigid as most languages do not allow you to derive from more than one type. So the goose is more or less cooked once you derive from TypeA.

My acid test for the above is:

  • Does TypeB want to expose the complete interface (all public methods no less) of TypeA such that TypeB can be used where TypeA is expected? Indicates Inheritance.

    • e.g. A Cessna biplane will expose the complete interface of an airplane, if not more. So that makes it fit to derive from Airplane.
  • Does TypeB want only some/part of the behavior exposed by TypeA? Indicates need for Composition.

    • e.g. A Bird may need only the fly behavior of an Airplane. In this case, it makes sense to extract it out as an interface / class / both and make it a member of both classes.

Update: Just came back to my answer and it seems now that it is incomplete without a specific mention of Barbara Liskov's Liskov Substitution Principle as a test for 'Should I be inheriting from this type?'

Casing answered 10/9, 2008 at 3:4 Comment(26)
The second example is straight out of the Head First Design Patterns (amazon.com/First-Design-Patterns-Elisabeth-Freeman/dp/…) book :) I would highly recommend that book to anyone who was googling this question.Salangia
It's very clear, but it may miss something : "Does TypeB want to expose the complete interface (all public methods no less) of TypeA such that TypeB can be used where TypeA is expected?" But what if this is true, and TypeB also expose the complete interface of TypeC ? And what if TypeC hasn't been modeled yet ?Ledet
You allude to what I think should be the most basic test: "Should this object be usable by code which expects objects of (what would be) the base type". If the answer is yes, the object must inherit. If no, then it probably should not. If I had my druthers, languages would provide a keyword to refer to "this class", and provide a means of defining a class which should behave just like another class, but not be substitutable for it (such a class would have all "this class" references replaced with itself).Millicentmillie
"Cessna biplane will expose the complete interface of an airplane" does not look like a good analogy to me, and makes me think of "square-rectangle problem". Is "airplane" here an abstract class, one that does not fly and only has some specifications on paper? I prefer to think of inheritance examples like: "RedToyota < UnpaintedToyota < ToyotaChassis".Guaco
@Guaco - the point is 'Can I pass in a Cessna biplane to all clients that expect an airplane without surprising them?'. If yes, then chances are you want inheritance.Casing
@Gishu, thanks for the clarification. However, my opinion is that a producer cannot build just an "airplane", but a producer can build a Toyota chassis. So "airplane" here looks like it serves as an abstract class, that is like an "interface" for customer. I was trying to think of a good analogy of inheritance of ready-to-use classes. I've heard that OOP originated in an attempt to model states and changes of states of real-life objects, but IMO in real life it makes no sense to say that Bus and Motorcycle inherit from MotorVehicle.Guaco
About airplane analogy, i would prefer: CessnaBiplanePilot < PilotSchoolStudent.Guaco
I'm actually struggling to think of any examples where inheritance would have been my answer, I often find aggregation, composition and interfaces result in more elegant solutions. Many of the above examples could possibly be better explained using those approaches...Nice
@Millicentmillie your comment is a good way to explain how to make the choice. If you cannot change the type of object a method accepts, then you are forced to subclass. Otherwise composition is preferred.Mouton
@Alexey: your example fails the "is a" test: RedToyota is not a ToyotaChassis, so RedToyota shouldn't inherit from ToyotaChassis. Likewise, CessnaBiplanePilot "is a" PilotSchoolStudent is also wrong.Nafis
@Lie Ryan: i think it depends on what is understood by "is a" (can you give a formal definition?). A square is a rectangle, but in certain contexts you cannot inherit Square from Rectangle (en.wikipedia.org/wiki/Circle-ellipse_problem). I am not convinced that without further precisions "is a" is a meaningful test.Guaco
I can say that RedToyota is a ToyotaChassis with some stuff mounded on it (which i may not need). And i can say that CessnaBiplanePilot knows at least as much as an average PilotSchoolStudent, and could take notes or pass exams in his place.Guaco
@Alexey: I think there's no controversy about the definition of "is a" test, it's supposed to mean "A is a (kind of) B". What is controversial is whether or not "Square is a Rectangle" depends on what you meant by Square and Rectangle. One you've properly defined the properties you want out of a Square and a Rectangle, the Circle-Ellipse problem will have an obvious solution.Nafis
I do not see in what sense "is a" is less controversial than "whether square is a rectangle". A square is a rectangle, but probably a mutable square is not a mutable rectangle. Whether something "is a" something else depends on how it is intended to be used, otherwise i do not see how it would possible to say that one data structure IS another (different) data structure.Guaco
In the 2nd example: Wouldn't I just create a class Flyable and subclass with Airplane and Bird? I don't see where composition would fit in this example.Emelyemelyne
@ViktorLexington - what if Bird already had to subclass Vertebrate ? Even if the language allows multiple inheritance - it usually results in a messier type designCasing
Lets talk about real life example which from time to time I rememeber. I need to return data in formated way. Like array('status' => 'succes', 'data' => $data$). I want to have this format in one place and so I have it in function. Now I alwayws add class as dependency for this funciton. But many dependencies are bad, so that sucks. So I am thinking that I could add this function to parent class. But I do not understand from Biplane - Airplane examples. Can I inherit and how would I call base class then? Maybe just 'BaseClass' and thats it?Do I have to use all methods from base class in child?Myocardiograph
A RedToyota has-a ToyotaChassis (but may not); a RedToyata has-a Chassis, which may or may not be a ToyotaChassis. A RedToyota is also not a great example because a Car has-a color, and a brand. And, of course, there are the inevitable flying car discussions. UI components are still among the best examples of inheritance available.Phototopography
@Salangia It's a great book, but the Ducks example seems broken. Even though they used composition, in the end the RubberDuck class still is-a Duck, and as such it still suffers from a rigid design. The FlyNoWay class' empty fly() method is the same as an empty fly() in a bad use of inheritance in the first place. This might also violate the LSP, since clients of all Duck objects are going to expect them to performFly(). A rubber duck that does performFly() won't have moved, for example, and the client might expect a duck to not be in the same place after flying.Kriss
@Casing not sure if this statement is generally applicable to determine if class should inherit - Does TypeB want to expose the complete interface (all public methods no less) of TypeA such that TypeB can be used where TypeA is expected? Indicates Inheritance For example, if I have Rectangle class and I want red color rectangle. I should not create RedRectangle inheriting from Rectangle. It is more like Rectangle should compose Color class. Isn't ?Freewheel
My problem with this answer is that it claims "but do not use a compose-always approach" without explaining why. In my experience in Banking, CRMs, Digital document management Inheritance is always an annoying obstacle that has to be refactored out. Because our "classifications" are always too naive & don't fit reality. Even biologists have complains about hierarchical taxonomy. Inheritance is good only with interfaces, in which case is just good ole ad hoc polymorphism in other languages like Haskell.Crossopterygian
@Casing the "it" pronouns are ambiguous in this sentence: In this case, it makes sense to extract **it** out as an interface / class / both and make **it** a member of both classes. Are you referring to the "fly" behaviour?Satisfaction
@Casing By applying your first test (basically LCP), is the following true? A. Define class HumanBeing; B. Define class HasBannaHumanBeing; C. Since HasBannaHumanBeing want to expose the complete interface of HumanBeing, HasBannaHumanBeing must inherit HumanBeing.Heywood
I would like to add some minor/transient info here and call out one of my favorite breakdowns of this axiom which is Item 18 from Joshua Bloch's Effective Java, Third Edition. It both lays out when inheritance is appropriate for reuse but also uses a clear example of inheritance breaking encapsulation and the consequences based on issues encountered by Java language designers while updating the collections api for modern Java versions. A good resource along with the Head First publication mentioned earlier.Pedicab
@Casing "** if not more**. So that makes it fit to derive from Airplane." What do you want me to pay attention to by say "if not more"?Biquadratic
Liskov's principle is not pertinent since the question regards design. Btw Bertrand Mayer's design by contract is more pertinent. Pity that vapid, hot-airish, answers get so much votes. While the top answer (with more votes), with just a link to wikipedia, deserves them all.Blackboard
T
568

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.

Templin answered 8/9, 2008 at 2:9 Comment(12)
This is not always a perfect approach, it's simply a good guideline. the Liskov Substitution Principle is much more accurate (fails less).Emblem
Can't you convert most is a to has a relationships? Hence a car has a basicVehicle object and a person has a basicMammal object, etc.Pawsner
"My car has a vehicle." If you consider that as a separate sentence, not in a programming context, that makes absolutely no sense. And that's the whole point of this technique. If it sounds awkward, it is probably wrong.Templin
@Nick Sure, but "My Car has a VehicleBehavior" makes more sense (I guess your "Vehicle" class could be named "VehicleBehavior"). So you cannot base your decision on "has a" vs "is a" comparision, you have to use LSP, or you will make mistakesLedet
Instead of "is a" think of "behaves like." Inheritance is about inheriting behavior, not just semantics.Wahlstrom
@Wahlstrom "Behaves like" can be achieved via interfaces without the need for inheritance. From Wikipedia: "An implementation of composition over inheritance typically begins with the creation of various interfaces representing the behaviors that the system must exhibit...Thus, system behaviors are realized without inheritance."Wheedle
@Wheedle Yes, and this is what the previous comment is really begging for. But this question is about inheritance, and when we extend a class, we do inherit the behavior of the parent. That's all I'm saying. Of course interfaces should be preferred over inheritance.Wahlstrom
This doesn't answer the question. The question is "why" not "what".Inverse
VehicleBehavior is a behavior (mobility behavior) not an entity. So VehicleBehavior is neither a part or Superclass for the type Car. Having some behavior/treat is better modeled by including a Mixin Class the represent this behavior.Cutlor
I don't see why behaves-like is better. When X inherits from Y, then yes, X behaves-like Y. But, you can't flip that around and use behaves-like as a tool to decide when to inherit, after all, a cat behaves-like a dog in many ways. You'd have to add a lot of asterisks to the behave-like rule to coerce it to work, and by then, you'd basically be explaining Liskov's Substitution. Can't we just toss is-a/has-a/behaves-like and say you can't inherit unless it obeys Liskov's substitution, and even then, other code-reuse and polymorphic tools may do the job better, depending on the job.Copt
@Wahlstrom you can't think "is a" is like "behaves" simply because if BMW is inherited from a car, it is a car and have all the car behaviors (push the gas pedal will speed up etc.) and PROPERTIES (color, wheels etc.). On the other hand, a cat and a chicken will run away (behavior) if they get scared, hence cat is not a chicken :-D. Because two entities behave the same does not leads to "is a" relationship.Hieratic
@Hieratic You are correct that a class that extends another does inherit the member variables of the parent. But: "Because two entities behave the same does not leads to 'is a' relationship" Yes, it does. In OO, we care more about substitutability based on the interface that an object has, rather than its concrete type. Member variables should be "hidden" or "private" and exposed via methods that form the object's API. This enables us to care about behavior, and not concrete types. Check out Sandi Metz 'Polly want a message' or the 'Devs for Ukraine' presentation, I think you will like it.Wahlstrom
K
281

If you understand the difference, it's easier to explain.

Procedural Code

An example of this is PHP without the use of classes (particularly before PHP5). All logic is encoded in a set of functions. You may include other files containing helper functions and so on and conduct your business logic by passing data around in functions. This can be very hard to manage as the application grows. PHP5 tries to remedy this by offering a more object-oriented design.

Inheritance

This encourages the use of classes. Inheritance is one of the three tenets of OO design (inheritance, polymorphism, encapsulation).

class Person {
   String Title;
   String Name;
   Int Age
}

class Employee : Person {
   Int Salary;
   String Title;
}

This is inheritance at work. The Employee "is a" Person or inherits from Person. All inheritance relationships are "is-a" relationships. Employee also shadows the Title property from Person, meaning Employee.Title will return the Title for the Employee and not the Person.

Composition

Composition is favoured over inheritance. To put it very simply you would have:

class Person {
   String Title;
   String Name;
   Int Age;

   public Person(String title, String name, String age) {
      this.Title = title;
      this.Name = name;
      this.Age = age;
   }

}

class Employee {
   Int Salary;
   private Person person;

   public Employee(Person p, Int salary) {
       this.person = p;
       this.Salary = salary;
   }
}

Person johnny = new Person ("Mr.", "John", 25);
Employee john = new Employee (johnny, 50000);

Composition is typically "has a" or "uses a" relationship. Here the Employee class has a Person. It does not inherit from Person but instead gets the Person object passed to it, which is why it "has a" Person.

Composition over Inheritance

Now say you want to create a Manager type so you end up with:

class Manager : Person, Employee {
   ...
}

This example will work fine, however, what if Person and Employee both declared Title? Should Manager.Title return "Manager of Operations" or "Mr."? Under composition this ambiguity is better handled:

Class Manager {
   public string Title;
   public Manager(Person p, Employee e)
   {
      this.Title = e.Title;
   }
}

The Manager object is composed of an Employee and a Person. The Title behaviour is taken from Employee. This explicit composition removes ambiguity among other things and you'll encounter fewer bugs.

Kado answered 21/5, 2009 at 7:54 Comment(21)
For inheritence: There is no ambiguity. You are implementing the Manager class based on requirements. So you would return "Manager of Operations" if thats what your requirements specified, else you would just use the base class's implementation. Also you could make Person an abstract class and thereby make sure down-stream classes implement a Title property.Cabinetwork
Its important to remember that one might say "Composition over inheritence" but that does not mean "Composition always over Inheritence". "Is a" means inheritence and leads to code reuse. Employee is a Person (Employee does not have a person).Cabinetwork
You would have to know at the time of creating the initial person class that you want to be able to change what title means, abstract properties are a sign of poor design, behavior should be abstract, not state.Dazzle
The example is confusing.Employee is a person, so it should use inheritance. You should not use composition for this example, because it is wrong relationship in domain model, even if technically you can declare it in the code.Chamorro
Here's more about composition implementations (and limitations): stackoverflow.com/questions/554145/…Heteroousian
I actually quite like this example, because, what if an Employee is both a Manager and and an Agent. In environments where you can't inherit from more that one class, you have a problem and you most likely end up with duplicate data. With composition you can handle this in an elegant way. And the overhead is minimal, even in environments where multiple inheritance is possible I would prefer this solution.Lauer
Classes certainly aren't required for composing things together. Indeed, classes often prevent composition by hiding the composable bits inside application-specific wrappers.Farthest
@netiul, it's still not that good an example: a better model would be that an Employee is a Person, but has a Role.Steffens
@Steffens It's the same idea. Being an Employee is some kind of a role. I'm an Employee but I'm also a Father. So make Employee and Father a Role and compose them with the same Person.Lauer
I disagree with this example. An Employee is-a Person, which is a textbook case of proper use of inheritance. I also think that the "issue" the redefinition of the Title field does not make sense. The fact that Employee.Title shadows Person.Title is a sign of poor programming. After all, are "Mr." and "Manager of Operations" really referring to the same aspect of a person (lowercase)? I would rename Employee.Title, and thus be able to reference the Title and JobTitle attributes of an Employee, both of which make sense in real life. Furthermore, there is no reason for Manager (continued...)Pavonine
(... continued) to inherit from both Person and Employee -- after all, Employee already inherits from Person. In more complex models, where a person might be a Manager and an Agent, it is true that multiple inheritance can be used (carefully!), but it would be preferable in many environments to have an abstract Role class from which Manager (contains Employees s/he manages) and Agent (contains Contracts, and other information) inherit. Then, an Employee is-a Person who has-multiple Roles. Thus, both composition and inheritance are used properly.Pavonine
@raxod502 Textbook examples are often wrong - after all, textbooks simplify reality as much as they can, to focus on one key concept at a time. And it sounds like you didn't read the previous comments, which show why it can very well be the wrong relationship - and those aren't some weird outliers, they're the kind of problem you see in almost every kind of application. I actually use inheritance less and less over time - it just doesn't quite seem to pay rent for most design. Liskov's Substitution Principle seems to be the best "back-of-the-hand" quick decider in my experience.Perceptual
@Perceptual I've re-read the previous comments, and don't understand what you think is wrong with my model's relationships. Also, by "textbook", I meant "conforming to or corresponding to a standard or type that is prescribed or widely held by theorists", not "from a literal textbook". As in, if the best way to describe the relationship between A and B is "A is a special type of B", then most people agree inheritance is the most appropriate approach to the situation.Pavonine
@raxod502 But whether Employee is a Person depends on your domain and overal design. As netiul noted, it may be much more practical for Employee to be a role of Person (i.e. "Person has an Employee, Manager, Son role"). What if you're both Agent and Manager? Or your Manager is a Company? Do your theorists recommend using inheritance like this in a language that doesn't support multiple inheritance? Textbook examples usually have a context within which they make sense; a lot of the papers written on inheritance assume multiple inheritance to be possible (and desirable).Perceptual
@Perceptual OK, I was assuming that the software was some sort of employee management system. Of course if you want an extremely general model capable of handling every aspect of people and their actions, then you would need to make a Person class (or something more general?) with (extremely general) Roles and every sort of attribute a Person could possibly have. Here composition is obviously superior. But in many real-world systems, you have a much simpler (and better-defined) model—the complexity being in the actual functionality of the code—and inheritance is a more elegant approach.Pavonine
@raxod502 The thing is, while I've used (and observed) inheritance for years, I've never seen elegancy in it. Combining state and behaviour? Sure. Virtual dispatch? Sure. But inheritance? It only really works when you have a tree-like hierarchy, and then after half a year of development you suddenly notice that your hierarchy is no longer tree-like and you can start over. That said, it's definitely true that many modern languages have poor support for composition - which may make composition a lot clunkier than inheritance in some cases (e.g. having to explicitly route interfaces to children).Perceptual
@Luann OK—I certainly concede that in some cases composition is preferable. Composition, however, just like inheritance, can be either the perfect tool or exactly the wrong tool, depending on the situation. My main point is the answer is invalid because it prescribes composition always, and then tries to shoehorn it into an example where it doesn't fit. (The model in the example would be better off with a combination of both composition and inheritance, as I described in my first comment.)Pavonine
Object lifecycle should be considered when choosing inheritance. Manager "is an" Employee is no good if the Manager chooses a different role and then all of their persistent Employee data has to be destroyed then recreated.Indispose
In inheritance modeling between Person and Employee, i would investigate the possibility of modeling this problem through an association of type has-a between Person and Job (naturally paid). Therefore, if a person has a job, the person will have a salary, and this association should be mapped as composition.Lussier
IMO, 'composition over inheritance' is a work-around for situations where design smells are present in your domain model. I think this answer goes a long way toward proving that point. If you come across sub-type anomalies (such as a property that needs a new value, like the title property in the example,) there are most likely mistakes in the model. Everything in the Person class should be true for ALL people. If not, it should not be in the super in the first place. As long as you follow this rule, you will not have issues defining the sub-types.Later
Work arounds, such as defining is-a relationships using composition, may get you by at the moment, but they will also mask the underlying issues. Eventually, these issues add up.Later
L
216

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 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.

Libre answered 21/5, 2009 at 8:34 Comment(4)
This is one of the better answers, in my opinion - I will add to this that trying to re-think your problems in terms of composition, in my experience, tends to lead to smaller, simpler, more self-contained, more reusable classes, with a clearer, smaller, more focused scope of responsibility. Often this means there is less need for things like dependency injection or mocking (in tests) as smaller components are usually able to stand on their own. Just my experience. YMMV :-)Wiredraw
The last paragraph in this post really clicked for me. Thank you.Hakenkreuz
Even though you mention a good technique, I don't think you're answering the question. It's not comparing runtime against compile time, but inheritance against composition, which REUSES code from either ONE or MANY classes and can OVERRIDE or ADD new logic. What you describe as object composition, is simply injecting logic via objects assigned as properties in a class, which is a great alternative for runtime manipulation. Thanks!Bernardinabernardine
Inheritance exposes a subclass to details of its parent class implementation...Is this through protected members?Tonl
B
112

Another, very pragmatic reason, to prefer composition over inheritance has to do with your domain model, and mapping it to a relational database. It's really hard to map inheritance to the SQL model (you end up with all sorts of hacky workarounds, like creating columns that aren't always used, using views, etc). Some ORMLs try to deal with this, but it always gets complicated quickly. Composition can be easily modeled through a foreign-key relationship between two tables, but inheritance is much harder.

Backbite answered 8/9, 2008 at 2:48 Comment(0)
C
104

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.

Creath answered 8/5, 2009 at 22:29 Comment(1)
The right tool for the right job. A hammer may be better at pounding things than a wrench, but that doesn't mean one should view a wrench as "an inferior hammer". Inheritance can be helpful when the things that are added to the subclass are necessary for the object to behave as a superclass object. For example, consider a base class InternalCombustionEngine with a derived class GasolineEngine. The latter adds things like spark plugs, which the base class lacks, but using the thing as an InternalCombustionEngine will cause the spark plugs to get used.Millicentmillie
M
75

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.

Mazda answered 14/9, 2015 at 5:22 Comment(2)
I think you mean subclassing entails subtyping, as is the case with most OOP languages. To rephrase, "Subclassing means implicit reuse of method implementations AND conforming to a type (interface) signature.Cambogia
Point number 3 does not break encapsulation as claimed, as it is the parent that decides whether members are protected or private. You want your parent class fully encapsulated? Declare everything private: job done. You want to use protected for the purpose for which it exists? Then use it, and rest assured that you aren't exposing anything that you didn't intend to be exposed.Blau
P
65

Inheritance is pretty enticing especially coming from procedural-land and it often looks deceptively elegant. I mean all I need to do is add this one bit of functionality to some other class, right? Well, one of the problems is that

inheritance is probably the worst form of coupling you can have

Your base class breaks encapsulation by exposing implementation details to subclasses in the form of protected members. This makes your system rigid and fragile. The more tragic flaw however is the new subclass brings with it all the baggage and opinion of the inheritance chain.

The article, Inheritance is Evil: The Epic Fail of the DataAnnotationsModelBinder, walks through an example of this in C#. It shows the use of inheritance when composition should have been used and how it could be refactored.

Phobia answered 23/1, 2010 at 19:55 Comment(2)
Inheritance isn't good or bad, it's merely a special case of Composition. Where, indeed, the subclass is implementing a similar functionality to the superclass. If your proposed subclass is not re-implementing but merely using the functionality of the superclass, then you have used Inheritance incorrectly. That is the programmer's mistake, not a reflection on Inheritance.Indigestible
This entire answer appears to be based on the author's ignorance of the difference between private and protected, as it gives literally no other problem than one issue (that could theoretically be) caused by not knowing basic keywords.Blau
U
61

When can you use composition?

You can always use composition. In some cases, inheritance is also possible and may lead to a more powerful and/or intuitive API, but composition is always an option.

When can you use inheritance?

It is often said that if "a bar is a foo", then the class Bar can inherit the class Foo. Unfortunately, this test alone is not reliable, use the following instead:

  1. a bar is a foo, AND
  2. bars can do everything that foos can do.

The first test ensures that all getters of Foo make sense in Bar (= shared properties), while the second test makes sure that all setters of Foo make sense in Bar (= shared functionality).

Example: Dog/Animal

A dog is an animal AND dogs can do everything that animals can do (such as breathing, moving, etc.). Therefore, the class Dog can inherit the class Animal.

Counter-example: Circle/Ellipse

A circle is an ellipse BUT circles can't do everything that ellipses can do. For example, circles can't stretch, while ellipses can. Therefore, the class Circle cannot inherit the class Ellipse.

This is called the Circle-Ellipse problem, which isn't really a problem, but more an indication that "a bar is a foo" isn't a reliable test by itself. In particular, this example highlights that derived classes should extend the functionality of base classes, never restrict it. Otherwise, the base class couldn't be used polymorphically. Adding the test "bars can do everything that foos can do" ensures that polymorphic use is possible, and is equivalent to the Liskov Substitution Principle:

Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it

When should you use inheritance?

Even if you can use inheritance doesn't mean you should: using composition is always an option. Inheritance is a powerful tool allowing implicit code reuse and dynamic dispatch, but it does come with a few disadvantages, which is why composition is often preferred. The trade-offs between inheritance and composition aren't obvious, and in my opinion are best explained in lcn's answer.

As a rule of thumb, I tend to choose inheritance over composition when polymorphic use is expected to be very common, in which case the power of dynamic dispatch can lead to a much more readable and elegant API. For example, having a polymorphic class Widget in GUI frameworks, or a polymorphic class Node in XML libraries allows to have an API which is much more readable and intuitive to use than what you would have with a solution purely based on composition.

Undeviating answered 3/6, 2016 at 22:23 Comment(12)
The circle-ellipse and square-rectangle scenarios are poor examples. Subclasses are invariably more complex than their superclass, so the problem is contrived. This problem is solved by inverting the relationship. An ellipse derives from a circle and a rectangle derives from a square. It's extremely silly to use composition in these scenarios.Pinkerton
@FuzzyLogic Agreed, but in fact, my post never advocates for using composition in this case. I've only said that the circle-ellipse problem is a great example of why "is-a" is not a good test alone to conclude that Circle should derive from Ellipse. Once we conclude that actually, Circle shouldn't derive from Ellipse due to violation of LSP, then possible options are to invert the relationship, or use composition, or use template classes, or use a more complex design involving additional classes or helper functions, etc... and the decision obviously should be taken on a case-by-case basis.Undeviating
@FuzzyLogic And if you are curious about what I would advocate for the specific case of Circle-Ellipse: I would advocate not implementing the Circle class. The issue with inverting the relationship is that it also violates LSP: imagine the function computeArea(Circle* c) { return pi * square(c->radius()); }. It is obviously broken if passed an Ellipse (what does radius() even mean?). An Ellipse is not a Circle, and as such shouldn't derive from Circle.Undeviating
computeArea(Circle *c) { return pi * width * height / 4.0; } Now it's generic.Pinkerton
@FuzzyLogic I disagree: you realize that this means that the class Circle anticipated the existence of the derived class Ellipse, and therefore provided width() and height()? What if now a library user decides to create another class called "EggShape"? Should it also derive from "Circle"? Of course not. An egg-shape is not a circle, and an ellipse is not a circle either, so none should derive from Circle since it breaks LSP. Methods performing operation on a Circle* class make strong assumptions about what a circle is, and breaking these assumptions will almost certainly lead to bugs.Undeviating
@FuzzyLogic More precisely, by adding the (possibly virtual) functions width() and height() to Circle, you didn't truly make the class generic. You just made it "slightly" more generic, and the concept that your class now represents is in fact CircleOrEllipse, which would be a better name for this class. But yet a better design is to have a class Shape with a virtual method computeArea(), and two independent subclasses called Circle and Ellipse. One has a method radius() while the other has two methods width() and height().Undeviating
I was just kidding :) My only bone was wedging the problem into the composition model but you cleared that up.Pinkerton
@FuzzyLogic Ah, sorry, didn't get the sarcasm :)Undeviating
You are awesome, loved this answer :)Aliquant
@Aliquant Thanks, I'm glad the answer was helpful!Undeviating
Very helpful answer. Just one further question: In the case of GUI or XML processing, do you mean subclassing (inheritance) can lead to an elegant API, or subtyping (interface "inheritance/implementation")Cambogia
@Cambogia I would say both. Let's use GUI widgets as an example. Subtyping alone (= sharing the interface) allows polymorphism and makes it easier to use widgets. In addition, subclassing (= also sharing the base implementation) makes it easier to implement new widgets. For example, in QtWidgets (C++), if you want to implement a new button type, you can inherit from QPushButton (both its interface and implementation), and you just need the reimplement a few methods to customize what you need.Undeviating
C
50

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.

Corncrib answered 8/9, 2008 at 2:25 Comment(3)
+1 I've found less and less that inheritance works in most situations. I much prefer shared/inherited interfaces and composition of objects....or is it called aggregation? Don't ask me, I've got a EE degree!!Zellazelle
I believe that this is the most common scenario where "composition over inheritance" applies since both could be fitting in theory. For instance, in a marketing system you might have a the concept of a Client. Then, a new concept of a PreferredClient pops up later on. Should PreferredClient inherit Client? A preferred client 'is a' client afterall, no? Well, not so fast... like you said objects cannot change their class at runtime. How would you model the client.makePreferred() operation? Perhaps the answer lies in using composition with a missing concept, an Account perhaps?Lathan
Rather than having different type of Client classes, perhaps there's just one that encapsulates the concept of an Account which could be a StandardAccount or a PreferredAccount...Lathan
G
39

Personally I learned to always prefer composition over inheritance. There is no programmatic problem you can solve with inheritance which you cannot solve with composition; though you may have to use Interfaces(Java) or Protocols(Obj-C) in some cases. Since C++ doesn't know any such thing, you'll have to use abstract base classes, which means you cannot get entirely rid of inheritance in C++.

Composition is often more logical, it provides better abstraction, better encapsulation, better code reuse (especially in very large projects) and is less likely to break anything at a distance just because you made an isolated change anywhere in your code. It also makes it easier to uphold the "Single Responsibility Principle", which is often summarized as "There should never be more than one reason for a class to change.", and it means that every class exists for a specific purpose and it should only have methods that are directly related to its purpose. Also having a very shallow inheritance tree makes it much easier to keep the overview even when your project starts to get really large. Many people think that inheritance represents our real world pretty well, but that isn't the truth. The real world uses much more composition than inheritance. Pretty much every real world object you can hold in your hand has been composed out of other, smaller real world objects.

There are downsides of composition, though. If you skip inheritance altogether and only focus on composition, you will notice that you often have to write a couple of extra code lines that weren't necessary if you had used inheritance. You are also sometimes forced to repeat yourself and this violates the DRY Principle (DRY = Don't Repeat Yourself). Also composition often requires delegation, and a method is just calling another method of another object with no other code surrounding this call. Such "double method calls" (which may easily extend to triple or quadruple method calls and even farther than that) have much worse performance than inheritance, where you simply inherit a method of your parent. Calling an inherited method may be equally fast as calling a non-inherited one, or it may be slightly slower, but is usually still faster than two consecutive method calls.

You may have noticed that most OO languages don't allow multiple inheritance. While there are a couple of cases where multiple inheritance can really buy you something, but those are rather exceptions than the rule. Whenever you run into a situation where you think "multiple inheritance would be a really cool feature to solve this problem", you are usually at a point where you should re-think inheritance altogether, since even it may require a couple of extra code lines, a solution based on composition will usually turn out to be much more elegant, flexible and future proof.

Inheritance is really a cool feature, but I'm afraid it has been overused the last couple of years. People treated inheritance as the one hammer that can nail it all, regardless if it was actually a nail, a screw, or maybe a something completely different.

Gymnasiast answered 31/1, 2013 at 19:34 Comment(2)
"Many people think that inheritance represents our real world pretty well, but that isn't the truth." So much this! Contrary to pretty much all the programming tutorials in the world ever, modeling real-world objects as inheritance chains is probably a bad idea in the long run. You should use inheritance only when there's an incredibly obvious, innate, simple is-a relationship. Like TextFile is a File.Havens
@Havens Even TextFile is-a File could be modeled without too much trouble via other techniques. For example, you could make "File" be an interface, with concrete TextFile and BinaryFile implementations, or, maybe a "File" is a class that can be instantiated with an instance of BinaryFileBehaviors or TextFileBehaviors (i.e. using the strategy pattern). I've given up on is-a, and now just follow the mantra of "inheritance is a last resort, use it when no other option will work sufficiently".Copt
G
27

My general rule of thumb: Before using inheritance, consider if composition makes more sense.

Reason: Subclassing usually means more complexity and connectedness, i.e. harder to change, maintain, and scale without making mistakes.

A much more complete and concrete answer from Tim Boudreau of Sun:

Common problems to the use of inheritance as I see it are:

  • Innocent acts can have unexpected results - The classic example of this is calls to overridable methods from the superclass constructor, before the subclasses instance fields have been initialized. In a perfect world, nobody would ever do that. This is not a perfect world.
  • It offers perverse temptations for subclassers to make assumptions about order of method calls and such - such assumptions tend not to be stable if the superclass may evolve over time. See also my toaster and coffee pot analogy.
  • Classes get heavier - you don't necessarily know what work your superclass is doing in its constructor, or how much memory it's going to use. So constructing some innocent would-be lightweight object can be far more expensive than you think, and this may change over time if the superclass evolves
  • It encourages an explosion of subclasses. Classloading costs time, more classes costs memory. This may be a non-issue until you're dealing with an app on the scale of NetBeans, but there, we had real issues with, for example, menus being slow because the first display of a menu triggered massive class loading. We fixed this by moving to more declarative syntax and other techniques, but that cost time to fix as well.
  • It makes it harder to change things later - if you've made a class public, swapping the superclass is going to break subclasses - it's a choice which, once you've made the code public, you're married to. So if you're not altering the real functionality to your superclass, you get much more freedom to change things later if you use, rather than extend the thing you need. Take, for example, subclassing JPanel - this is usually wrong; and if the subclass is public somewhere, you never get a chance to revisit that decision. If it's accessed as JComponent getThePanel() , you can still do it (hint: expose models for the components within as your API).
  • Object hierarchies don't scale (or making them scale later is much harder than planning ahead) - this is the classic "too many layers" problem. I'll go into this below, and how the AskTheOracle pattern can solve it (though it may offend OOP purists).

...

My take on what to do, if you do allow for inheritance, which you may take with a grain of salt is:

  • Expose no fields, ever, except constants
  • Methods shall be either abstract or final
  • Call no methods from the superclass constructor

...

all of this applies less to small projects than large ones, and less to private classes than public ones

Ghazi answered 21/5, 2012 at 1:59 Comment(0)
F
20

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.

Fusiform answered 8/9, 2008 at 2:29 Comment(0)
C
18

Inheritance creates a strong relationship between a subclass and super class; subclass must be aware of super class'es implementation details. Creating the super class is much harder, when you have to think about how it can be extended. You have to document class invariants carefully, and state what other methods overridable methods use internally.

Inheritance is sometimes useful, if the hierarchy really represents a is-a-relationship. It relates to Open-Closed Principle, which states that classes should be closed for modification but open to extension. That way you can have polymorphism; to have a generic method that deals with super type and its methods, but via dynamic dispatch the method of subclass is invoked. This is flexible, and helps to create indirection, which is essential in software (to know less about implementation details).

Inheritance is easily overused, though, and creates additional complexity, with hard dependencies between classes. Also understanding what happens during execution of a program gets pretty hard due to layers and dynamic selection of method calls.

I would suggest using composing as the default. It is more modular, and gives the benefit of late binding (you can change the component dynamically). Also it's easier to test the things separately. And if you need to use a method from a class, you are not forced to be of certain form (Liskov Substitution Principle).

Chopping answered 21/5, 2009 at 8:11 Comment(3)
It's worth noting that inheritance is not the only way to achieve polymorphism. The Decorator Pattern provides the appearance of polymorphism through composition.Trimolecular
@BitMask777: Subtype polymorphism is only one kind of polymorphism, another would be parametric polymorphism, you don't need inheritance for that. Also more importantly: when talking about inheritance, one means class inheritance; .i.e. you can have subtype polymorphism by having a common interface for multiple classes, and you don't get the problems of inheritance.Chopping
@engaga: I interpreted your comment Inheritance is sometimes useful... That way you can have polymorphism as hard-linking the concepts of inheritance and polymorphism (subtyping assumed given the context). My comment was intended to point out what you clarify in your comment: that inheritance is not the only way to implement polymorphism, and in fact is not necessarily the determining factor when deciding between composition and inheritance.Trimolecular
S
18

Suppose an aircraft has only two parts: an engine and wings.
Then there are two ways to design an aircraft class.

Class Aircraft extends Engine{
  var wings;
}

Now your aircraft can start with having fixed wings
and change them to rotary wings on the fly. It's essentially
an engine with wings. But what if I wanted to change
the engine on the fly as well?

Either the base class Engine exposes a mutator to change its
properties, or I redesign Aircraft as:

Class Aircraft {
  var wings;
  var engine;
}

Now, I can replace my engine on the fly as well.

Skittish answered 29/11, 2010 at 10:54 Comment(3)
Your post brings up a point I'd not considered before--to continue your an analogy of mechanical objects with multiple parts, on something like a firearm, there is generally one part marked with a serial number, whose serial number is considered to be that of the firearm as a whole (for a handgun, it would typically be the frame). One may replace all the other parts and still have the same firearm, but if the frame cracks and needs to be replaced, the result of assembling a new frame with all the other parts from the original gun would be a new gun. Note that...Millicentmillie
...the fact that multiple parts of a gun might have serial numbers marked on them does not mean that a gun can have multiple identities. Only the serial number on the frame identifies the gun; the serial number on any other part identifies which gun those parts were manufactured to be assembled with, which may not be the gun to which they are assembled at any given time.Millicentmillie
In this particular case of aircraft I would definitely not recommend to 'change the engine on the fly'Muskrat
C
18

If you want the canonical, textbook answer people have been giving since the rise of OOP (which you see many people giving in these answers), then apply the following rule: "if you have an is-a relationship, use inheritance. If you have a has-a relationship, use composition".

This is the traditional advice, and if that satisfies you, you can stop reading here and go on your merry way. For everyone else...

is-a/has-a comparisons have problems

For example:

  • A square is-a rectangle, but if your rectangle class has setWidth()/setHeight() methods, then there's no reasonable way to make a Square inherit from Rectangle without breaking Liskov's substitution principle.
  • An is-a relationship can often be rephrased to sound like a has-a relationship. For example, an employee is-a person, but a person also has-an employment status of "employed".
  • is-a relationships can lead to nasty multiple inheritance hierarchies if you're not careful. After all, there's no rule in English that states that an object is exactly one thing.
  • People are quick to pass this "rule" around, but has anyone ever tried to back it up, or explain why it's a good heuristic to follow? Sure, it fits nicely into the idea that OOP is supposed to model the real world, but that's not in-and-of-itself a reason to adopt a principle.

See this StackOverflow question for more reading on this subject.

To know when to use inheritance vs composition, we first need to understand the pros and cons of each.

The problems with implementation inheritance

Other answers have done a wonderful job at explaining the issues with inheritance, so I'll try to not delve into too many details here. But, here's a brief list:

  • It can be difficult to follow a logic that weaves between base and sub-class methods.
  • Carelessly implementing one method in your class by calling another overridable method will cause you to leak implementation details and break encapsulation, as the end-user could override your method and detect when you internally call it. (See "Effective Java" item 18).
  • The fragile base problem, which simply states that your end-user's code will break if they happen to depend on the leakage of implementation details when you attempt to change them. To make matters worse, most OOP languages allow inheritance by default - API designers who aren't proactively preventing people from inheriting from their public classes need to be extra cautious whenever they refactor their base classes. Unfortunately, the fragile base problem is often misunderstood, causing many to not understand what it takes to maintain a class that anyone can inherit from.
  • The deadly diamond of death

The problems with composition

  • It can sometimes be a little verbose.

That's it. I'm serious. This is still a real issue and can sometimes create conflict with the DRY principle, but it's generally not that bad, at least compared to the myriad of pitfalls associated with inheritance.

When should inheritance be used?

Next time you're drawing out your fancy UML diagrams for a project (if you do that), and you're thinking about adding in some inheritance, please adhere to the following advice: don't.

At least, not yet.

Inheritance is sold as a tool to achieve polymorphism, but bundled with it is this powerful code-reuse system, that frankly, most code doesn't need. The problem is, as soon as you publicly expose your inheritance hierarchy, you're locked into this particular style of code-reuse, even if it's overkill to solve your particular problem.

To avoid this, my two cents would be to never expose your base classes publicly.

  • If you need polymorphism, use an interface.
  • If you need to allow people to customize the behavior of your class, provide explicit hook-in points via the strategy pattern, it's a more readable way to accomplish this, plus, it's easier to keep this sort of API stable as you're in full control over what behaviors they can and can not change.
  • If you're trying to follow the open-closed principle by using inheritance to avoid adding a much-needed update to a class, just don't. Update the class. Your codebase will be much cleaner if you actually take ownership of the code you're hired to maintain instead of trying to tack stuff onto the side of it. If you're scared about introducing bugs, then get the existing code under test.
  • If you need to reuse code, start out by trying to use composition or helper functions.

Finally, if you've decided that there's no other good option, and you must use inheritance to achieve the code-reuse that you need, then you can use it, but, follow these four P.A.I.L. rules of restricted inheritance to keep it sane.

  1. Use inheritance as a private implementation detail. Don't expose your base class publicly, use interfaces for that. This lets you freely add or remove inheritance as you see fit without making a breaking change.
  2. Keep your base class abstract. It makes it easier to divide out the logic that needs to be shared from the logic that doesn't.
  3. Isolate your base and child classes. Don't let your subclass override base class methods (use the strategy pattern for that), and avoid having them expect properties/methods to exist on each other, use other forms of code-sharing to achieve that. Use appropriate language features to force all methods on the base class to be non-overridable ("final" in Java, or non-virtual in C#).
  4. Inheritance is a last resort.

The Isolate rule in particular may sound a little rough to follow, but if you discipline yourself, you'll get some pretty nice benefits. In particular, it gives you the freedom to avoid all of the main nasty pitfalls associated with the inheritance that were mentioned above.

  • It's much easier to follow the code because it doesn't weave in and out of base/sub classes.
  • You can not accidentally leak when your methods are internally calling other overridable methods if you never make any of your methods overridable. In other words, you won't accidentally break encapsulation.
  • The fragile base class problem stems from the ability to depend on accidentally leaked implementation details. Since the base class is now isolated, it will be no more fragile than a class depending on another via composition.
  • The deadly diamond of death isn't an issue anymore, since there's simply no need to have multiple layers of inheritance. If you have the abstract base classes B and C, which both share a lot of functionality, just move that functionality out of B and C and into a new abstract base class, class D. Anyone who inherited from B should update to inherit from both B and D, and anyone who inherited from C should inherit from C and D. Since your base classes are all private implementation details, it shouldn't be too difficult to figure out who's inheriting from what, to make these changes.

Conclusion

My primary suggestion would be to use your brain on this matter. What's far more important than a list of dos and don'ts about when to use inheritance is an intuitive understanding of inheritance and its associated pros and cons, along with a good understanding of the other tools out there that can be used instead of inheritance (composition isn't the only alternative. For example, the strategy pattern is an amazing tool that's forgotten far too often). Perhaps when you have a good, solid understanding of all of these tools, you'll choose to use inheritance more often than I would recommend, and that's completely fine. At least, you're making an informed decision, and aren't just using inheritance because that's the only way you know how to do it.

Further reading:

  • An article I wrote on this subject, that dives even deeper and provides examples.
  • A webpage talking about three different jobs that inheritance does, and how those jobs can be done via other means in the Go language.
  • A list of reasons why it can be good to declare your class as non-inheritable (e.g. "final" in Java).
  • The "Effective Java" book by Joshua Bloch, item 18, which discusses composition over inheritance, and some of the dangers of inheritance.
Copt answered 22/3, 2022 at 7:17 Comment(0)
H
13

You need to have a look at The Liskov Substitution Principle in Uncle Bob's SOLID principles of class design. :)

Howrah answered 5/10, 2010 at 11:57 Comment(0)
P
10

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.

Pickax answered 13/5, 2016 at 20:24 Comment(4)
That classes can't use multiple base classes is not a poor reflection on Inheritance but rather a poor reflection on a particular language's lack of capability.Indigestible
In the time since writing this answer, I read this post from "Uncle Bob" which addresses that lack of capability. I've never used a language that allows multiple inheritance. But looking back, the question is tagged "language agnostic" and my answer assumes C#. I need to broaden my horizons.Pickax
The second bullet point merely seems to be explaining the need for overrides, which I've never heard of a language that doesn't provide.Blau
That works if it was understood in advance which behaviors we’ll need to override and the class is organized to make that simple. Otherwise the result is confusing control flow or we still end up modifying other classes. It’s possible to do it for the right reasons and get it right. More often we couple unrelated classes to each other via a base class and it then the problems start to show up.Pickax
U
8

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.

Ulbricht answered 7/5, 2009 at 1:43 Comment(2)
@Anzurio....How do you differentiate API vs functionlaity? According to me exposed methods of a class we call them as api methods of that class. These are the functionality of the class as well. If you use composition, You use public methods of rhe class, we have already called them API.Pleat
@Pleat sorry for the confusion. The point I was trying to make is that, when using inheritance, you will expose the complete API of the parent class but, if the child class needn't expose that full parent's API, you use composition instead such that the child class will have access to the parent class' functionality without exposing its full API.Ulbricht
V
7

These two ways can live together just fine and actually support each other.

Composition is just playing it modular: you create interface similar to the parent class, create new object and delegate calls to it. If these objects need not to know of each other, it's quite safe and easy to use composition. There are so many possibilites here.

However, if the parent class for some reason needs to access functions provided by the "child class" for inexperienced programmer it may look like it's a great place to use inheritance. The parent class can just call it's own abstract "foo()" which is overwritten by the subclass and then it can give the value to the abstract base.

It looks like a nice idea, but in many cases it's better just give the class an object which implements the foo() (or even set the value provided the foo() manually) than to inherit the new class from some base class which requires the function foo() to be specified.

Why?

Because inheritance is a poor way of moving information.

The composition has a real edge here: the relationship can be reversed: the "parent class" or "abstract worker" can aggregate any specific "child" objects implementing certain interface + any child can be set inside any other type of parent, which accepts it's type. And there can be any number of objects, for example MergeSort or QuickSort could sort any list of objects implementing an abstract Compare -interface. Or to put it another way: any group of objects which implement "foo()" and other group of objects which can make use of objects having "foo()" can play together.

I can think of three real reasons for using inheritance:

  1. You have many classes with same interface and you want to save time writing them
  2. You have to use same Base Class for each object
  3. You need to modify the private variables, which can not be public in any case

If these are true, then it is probably necessary to use inheritance.

There is nothing bad in using reason 1, it is very good thing to have a solid interface on your objects. This can be done using composition or with inheritance, no problem - if this interface is simple and does not change. Usually inheritance is quite effective here.

If the reason is number 2 it gets a bit tricky. Do you really only need to use the same base class? In general, just using the same base class is not good enough, but it may be a requirement of your framework, a design consideration which can not be avoided.

However, if you want to use the private variables, the case 3, then you may be in trouble. If you consider global variables unsafe, then you should consider using inheritance to get access to private variables also unsafe. Mind you, global variables are not all THAT bad - databases are essentially big set of global variables. But if you can handle it, then it's quite fine.

Vig answered 16/4, 2013 at 20:15 Comment(0)
O
6

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.

Olid answered 8/9, 2008 at 3:0 Comment(0)
T
6

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.

Tomahawk answered 30/12, 2013 at 1:57 Comment(2)
You said inheritance and inheritance. don't you mean inheritance and composition?Bash
No, you don't. You can just as well define a canine interface and let every dog implement it and you'll end up with more SOLID code.Distaff
M
5

A simple way to make sense of this would be that inheritance should be used when you need an object of your class to have the same interface as its parent class, so that it can thereby be treated as an object of the parent class (upcasting). Moreover, function calls on a derived class object would remain the same everywhere in code, but the specific method to call would be determined at runtime (i.e. the low-level implementation differs, the high-level interface remains the same).

Composition should be used when you do not need the new class to have the same interface, i.e. you wish to conceal certain aspects of the class' implementation which the user of that class need not know about. So composition is more in the way of supporting encapsulation (i.e. concealing the implementation) while inheritance is meant to support abstraction (i.e. providing a simplified representation of something, in this case the same interface for a range of types with different internals).

Mort answered 4/6, 2014 at 11:36 Comment(1)
+1 for mention of interface. I use this approach often to hide existing classes and make my new class properly unit testable by mocking out the object used for composition. This requires the owner of the new object to pass it the candidate parent class instead.Md
E
4

Subtyping is appropriate and more powerful where the invariants can be enumerated, else use function composition for extensibility.

Evonevonne answered 2/12, 2011 at 7:40 Comment(0)
S
4

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.

Sherrer answered 7/12, 2011 at 10:40 Comment(0)
B
4

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).

Bercy answered 31/8, 2013 at 13:41 Comment(0)
A
4

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();
     }
} 
Anticipative answered 22/9, 2016 at 9:31 Comment(5)
I think it doesn't answer the questionLiterator
You can have re-look at OP question. I have addressed : What trade-offs are there for each approach?Anticipative
As you mentioned, you talk only about "pros of Inheritance and cons of Composition", and not the tradeoffs for EACH approach or the cases where you should use one over anotherLiterator
pros and cons provides trade-off since pros of inheritance is cons of composition and cons of composition is pros of inheritance.Anticipative
i am late to the party but; since cons of composition is pros of inheritence, you didnt talk about cons of inheritance. you only talked about pros of inheritance, twice.Marmoreal
G
3

A rule of thumb I have heard is inheritance should be used when its a "is-a" relationship and composition when its a "has-a". Even with that I feel that you should always lean towards composition because it eliminates a lot of complexity.

Gains answered 8/9, 2008 at 2:14 Comment(0)
P
2

As many people told, I will first start with the check - whether there exists an "is-a" relationship. If it exists I usually check the following:

Whether the base class can be instantiated. That is, whether the base class can be non-abstract. If it can be non-abstract I usually prefer composition

E.g 1. Accountant is an Employee. But I will not use inheritance because a Employee object can be instantiated.

E.g 2. Book is a SellingItem. A SellingItem cannot be instantiated - it is abstract concept. Hence I will use inheritacne. The SellingItem is an abstract base class (or interface in C#)

What do you think about this approach?

Also, I support @anon answer in Why use inheritance at all?

The main reason for using inheritance is not as a form of composition - it is so you can get polymorphic behaviour. If you don't need polymorphism, you probably should not be using inheritance.

@MatthieuM. says in https://softwareengineering.stackexchange.com/questions/12439/code-smell-inheritance-abuse/12448#comment303759_12448

The issue with inheritance is that it can be used for two orthogonal purposes:

interface (for polymorphism)

implementation (for code reuse)

REFERENCE

  1. Which class design is better?
  2. Inheritance vs. Aggregation
Precession answered 1/8, 2012 at 11:15 Comment(5)
I'm not sure why 'the base class is abstract?' figures into the discussion.. the LSP: will all functions that operate on Dogs work if Poodle objects are passed in ? If yes, then Poodle is can be substituted for Dog and hence can inherit from Dog.Casing
@Casing Thanks. I will definitely look into LSP. But before that, can you please provide an "example where inheritance is proper in which base class cannot be abstract". What I think is, inheritance is applicable only if base class is abstract. If base class need to be instantiated separately, do not go for inheritance. That is, even though Accountant is an Employee, do not use inheritance.Precession
been reading WCF lately. An example in the .net framework is SynchronizationContext (base + can be instantiated) which queues work onto a ThreadPool thread. Derivations include WinFormsSyncContext (queue onto UI Thread) and DispatcherSyncContext (queue onto WPF Dispatcher)Casing
@Casing Thanks. However, it would be more helpful if you can provide a scenario based on Bank domain, HR domain, Retail domain or any other popular domain.Precession
Sorry. I'm not familiar with those domains.. Another example if the previous one was too obtuse is the Control class in Winforms/WPF. The base/generic control can be instantiated. Derivations include Listboxes, Textboxes, etc. Now that I think of it, the Decorator Design pattern is a good example IMHO and useful too. The decorator derives from the non-abstract object that it wants to wrap/decorate.Casing
C
2

Composition v/s Inheritance is a wide subject. There is no real answer for what is better as I think it all depends on the design of the system.

Generally type of relationship between object provide better information to choose one of them.

If relation type is "IS-A" relation then Inheritance is better approach. otherwise relation type is "HAS-A" relation then composition will better approach.

Its totally depend on entity relationship.

Cypress answered 18/3, 2014 at 9:39 Comment(0)
B
2

I see no one mentioned the diamond problem, which might arise with inheritance.

In a glance, if classes B and C inherit A and both override method X, and a fourth class D, inherits from both B and C, and does not override X, which implementation of X D is supposed to use?

Wikipedia offers a nice overview of the topic being discussed in this question.

Berdichev answered 16/4, 2015 at 12:41 Comment(4)
D inherits B and C not A. If so, then it'd use the implementation of X that is in class A.Profundity
@fabricio: thanks, I edited the text. By the way, such scenario cannot occur in languages that do not allow multiple class inheritance, am I right ?Berdichev
yes you are right.. and I've never worked with one that allows multiple inheritance (as per the example in the diamond problem)..Profundity
It is not the problem at all as this is the basic way of scaling systems or reserving facilities and functionality for load balancing. Both the implementations are present, and it is up to the user or load balancing algorithm/rules to decide which one and when to apply. On the language level it is not a problem because even in your question all implementations of the method Xare identified with different qualified names.Hickox
U
1

This rule is a complete nonsense. Why?

The reason is that in every case it is possible to tell whether to use composition or inheritance. This is determined by the answer to a question: "IS something A something else" or "HAS something A something else".

You cannot "prefer" to make something to be something else or to have something else. Strict logical rules apply.

Also there are no "contrived examples" because in every situation an answer to this question can be given.

If you cannot answer this question there is something else wrong. This includes overlapping responsibilities of classess which are usually the result of wrong use of interfaces, less often by rewriting same code in different classess.

To avoid this situations I also recommend to use good names for classes , that fully resemble their responsibilities.

Unselfish answered 4/1, 2014 at 13:57 Comment(13)
Your point is a good one, though I think it should be phrased somewhat better; also, there are some borderline cases (you suggest there are none whatsoever). The key point is that in most cases, the decision is actually very straightforward and should not be considered a judgment call. The real question to answer in asking whether a Foo should be a Bar or contain one, will be whether it will be necessary to have any code operate on the Foo within a Bar *while retaining its identity as a Bar. If not, simply encapsulate a Foo and expose it as a member.Millicentmillie
No there are no borderline cases. Every case can be solved by factors that are not obvious at first. The matter requires a deep analysis, otherwise - arbitrary decision will cause problems leading to bad code.Unselfish
And only semantics can determine this. If you are in situation when you need any code to operate on the Foo within a Bar while retaining its identity as Bar - you shouldn't make decision upon this. You, as a designer of the class API should know whether to use delegates or expose that member.Unselfish
An object-oriented model of the universe should be regarded as a tool which is often useful to facilitate the solving of many real-world problems. Not all real-world problems are a good fit for an object-oriented model, however. Sometimes even when inheritance isn't a perfect fit for an object-oriented model, it may allow existing code to be used without modification in cases that would otherwise require more rework. Such usage may incur some "technical debt", but if the program is expected to be obsolete before that poses a problem, such obsolescence would essentially vacate any such debt.Millicentmillie
All real world problems can be solved using an object oriented model, because everything fits into a definition of object. Inheritance is the only fit for an object-oriented model. I know cases, where people search refugee in interfaces, traits or multiple inheritance because they are simply not capable of figuring out the correct inheritance. It's their code that represents technical debt, which actually means a negligence and ignorance. While algorithmic correctness comes from iterative process of trial and error - OOP doesn't allow any mistakes which instantly take their toll. . . .Unselfish
. . . And that is a reason why there is a lot of bad code around, a lot of bad practices are being taught (like SOLID, and AGILE). This approaches are presented as solution to programming pains. But there are no solutions, no golden rule. The pains will last forever because God cursed the earth, doing this things that those "technigques" have to "offer" actually add to these pains more and more, not mentioning that less good things come out of this. The software this days, as everybody can see is shallow, uninteresting, superficial and cheap. Unexciting and uncolorfull.Unselfish
In the real world, systems are periodically replaced. Well-designed systems have room for at least one layer of "kludge" changes to be implemented reliably if no further changes are ever required. If a new system will be coming on line in a month and the old system will have no usefulness past that time, but people need to add a new function to the old system ASAP, a kludge which can be implemented reliably in 48 hours may be preferable to a better-engineered solution which would take a week. If it turns out the new system never comes on-line, the kludge might cause pain later, but...Millicentmillie
...if the new system is installed on schedule, the extra effort required for a clean solution may be essentially wasted.Millicentmillie
They are replaced because they are all not perfect and they are not perfect because they are created with money in mind and not their users. That's the ultimate answer why they fail. This involves both sides: the producer which want to minimize costs and the consumer which doesn't want to spend enough time to analyse his real needs in order to maximize his profits by getting involved in other activities.Unselfish
"All real world problems can be solved using an object oriented model, because everything fits into a definition of object." All real world problems can also be solved by a Turing Machine, because everything fits into a definition of Turing Machine. That doesn't make it a good idea though.Farthest
leading in with "This rule is a complete nonsense" is a little obtuse, try making the points the strong statement.Highfalutin
It's not a rule, it's a principle. If it was a rule then one could logically interpret it as, "Never, ever inherit. Compose instead." A less experienced programmer needs that guidance. They're not going to intuitively going to know which is better, and they're likely to lean toward inheritance because learning materials emphasize it. And experienced programmers make bad choices too, so it's good for all of us.Pickax
Indeed, the question of the OP is rather pointless. It's like asking: "Which is better, train or boat?". If you're on an island with no bridges, the boat is better. If you are far away from the coast and the destination is connected to you by land, the train is better. In some situations, inheritance involves less work, in other situations, composition involves less work.Indigestible
U
1

Just opinion, inheritance should only be used when:

  • Both classes are in the same logical domain
  • The subclass is a proper subtype of the superclass
  • The superclass’s implementation is necessary or appropriate for the subclass
  • The enhancements made by the subclass are primarily additive.

There are times when all of these things converge:

  • Higher-level domain modeling
  • Frameworks and framework extensions
  • Differential programming
Undemonstrative answered 10/10, 2022 at 23:17 Comment(0)
A
0

What do you want to force yourself (or another programmer) to adhere to and when do you want to allow yourself (or another programmer) more freedom. It has been argued that inheritance is helpful when you want to force someone into a way of dealing with/solving a particular problem so they can't head off in the wrong direction.

Is-a and Has-a is a helpful rule of thumb.

Asexual answered 20/6, 2009 at 4:41 Comment(0)
L
0

Simply, implementation is like rules you (the class) should follow

But extend is like using common code for a lot of classes, and maybe just one of them that you need to override.

Loomis answered 16/5, 2022 at 13:41 Comment(0)
P
0

I am surprised that no current answer is from the abstract data type (ADT) perspective, which is the formal theory behind this sentence in many answers:

A is B or A has B

A class in OOP essentially defines an ADT, meaning an object of it

  1. promises a set of invariants that will hold throughout its lifetime. That is, the invariants are established by any of its constructors and maintained by all of its methods.
  2. provides a set of methods that one can use to manipulate the structure that the ADT encapsulates.

Therefore, to inherit a class, you will need to ensure that the child class

  1. also holds all the parent's invariants.
  2. at least provide all the virtual methods that the parent has specified for a user to manipulate it (whether just using the parent's implementation or doing something new), which must conform to the parent's virtual method specifications (i.e. you can strengthen the specs but cannot weaken them).

In contrast, to composite a class, or in other words, to use it as a field in a new class,

  1. you are not responsible for holding its invariants. In particular, the enclosing class is a different ADT that can hold a completely different set of invariants.
  2. you just use (some of) its methods to manipulate it --- you don't need to implement any of them. While you may still choose to expose some of its methods through the enclosing class via similar method specifications, it's not always necessary.

In conclusion, if you view inheritance vs. composition through the ADT perspective, you will be able to notice the essential differences between them, which will render the correct choice obvious in most situations.

Protonema answered 2/3 at 4:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.