Prefer composition over inheritance?

407,057

Solution 1

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?'

Solution 2

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.

Solution 3

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

Solution 4

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.

Solution 5

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.

Share:
407,057
readonly
Author by

readonly

Readonly

Updated on July 14, 2022

Comments

  • readonly
    readonly almost 2 years

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

    • 0xCAFEBABE
      0xCAFEBABE almost 16 years
    • Tomer Ben David
      Tomer Ben David almost 9 years
      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.
  • Bill K
    Bill K almost 16 years
    This is not always a perfect approach, it's simply a good guideline. the Liskov Substitution Principle is much more accurate (fails less).
  • Raj Rao
    Raj Rao over 13 years
    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.
  • Raj Rao
    Raj Rao over 13 years
    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).
  • Jeshurun
    Jeshurun about 13 years
    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.
  • Morgan Bengtsson
    Morgan Bengtsson almost 13 years
    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.
  • Nick Zalutskiy
    Nick Zalutskiy almost 13 years
    "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.
  • Tristan
    Tristan almost 13 years
    @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 mistakes
  • Tristan
    Tristan almost 13 years
    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 ?
  • supercat
    supercat over 12 years
    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).
  • Po-ta-toe
    Po-ta-toe over 12 years
    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.
  • ybakos
    ybakos about 12 years
    Instead of "is a" think of "behaves like." Inheritance is about inheriting behavior, not just semantics.
  • Gishu
    Gishu almost 12 years
    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.
  • LCJ
    LCJ almost 12 years
    @Gishu 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.
  • Gishu
    Gishu almost 12 years
    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)
  • LCJ
    LCJ almost 12 years
    @Gishu 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.
  • Gishu
    Gishu almost 12 years
    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.
  • supercat
    supercat almost 12 years
    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...
  • supercat
    supercat almost 12 years
    ...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.
  • BitMask777
    BitMask777 almost 12 years
    It's worth noting that inheritance is not the only way to achieve polymorphism. The Decorator Pattern provides the appearance of polymorphism through composition.
  • egaga
    egaga almost 12 years
    @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.
  • BitMask777
    BitMask777 over 11 years
    @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.
  • Alexey
    Alexey over 11 years
    "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".
  • Gishu
    Gishu over 11 years
    @Alexey - 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.
  • Alexey
    Alexey over 11 years
    @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.
  • Alexey
    Alexey over 11 years
    About airplane analogy, i would prefer: CessnaBiplanePilot < PilotSchoolStudent.
  • supercat
    supercat over 11 years
    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.
  • Stuart Wakefield
    Stuart Wakefield over 11 years
    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...
  • Kelvin
    Kelvin about 11 years
    @supercat 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.
  • Lie Ryan
    Lie Ryan about 11 years
    @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.
  • Alexey
    Alexey about 11 years
    @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.
  • Alexey
    Alexey about 11 years
    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.
  • Lie Ryan
    Lie Ryan about 11 years
    @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.
  • Alexey
    Alexey about 11 years
    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.
  • Michael Freidgeim
    Michael Freidgeim almost 11 years
    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.
  • cregox
    cregox almost 11 years
    Here's more about composition implementations (and limitations): stackoverflow.com/questions/554145/…
  • trevorKirkby
    trevorKirkby over 10 years
    You said inheritance and inheritance. don't you mean inheritance and composition?
  • supercat
    supercat over 10 years
    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.
  • luke1985
    luke1985 over 10 years
    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.
  • luke1985
    luke1985 over 10 years
    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.
  • supercat
    supercat over 10 years
    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.
  • luke1985
    luke1985 over 10 years
    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. . . .
  • luke1985
    luke1985 over 10 years
    . . . 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.
  • supercat
    supercat over 10 years
    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...
  • supercat
    supercat over 10 years
    ...if the new system is installed on schedule, the extra effort required for a clean solution may be essentially wasted.
  • luke1985
    luke1985 over 10 years
    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.
  • mindplay.dk
    mindplay.dk over 10 years
    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 :-)
  • netiul
    netiul about 10 years
    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.
  • Warbo
    Warbo about 10 years
    Classes certainly aren't required for composing things together. Indeed, classes often prevent composition by hiding the composable bits inside application-specific wrappers.
  • Warbo
    Warbo about 10 years
    "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.
  • Kell
    Kell about 10 years
    +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.
  • Celos
    Celos over 9 years
    @netiul, it's still not that good an example: a better model would be that an Employee is a Person, but has a Role.
  • netiul
    netiul over 9 years
    @Celos 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.
  • Radon Rosborough
    Radon Rosborough over 9 years
    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...)
  • Radon Rosborough
    Radon Rosborough over 9 years
    (... 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.
  • fabricio
    fabricio about 9 years
    D inherits B and C not A. If so, then it'd use the implementation of X that is in class A.
  • Veverke
    Veverke about 9 years
    @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 ?
  • fabricio
    fabricio about 9 years
    yes you are right.. and I've never worked with one that allows multiple inheritance (as per the example in the diamond problem)..
  • Binarian
    Binarian about 9 years
    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.
  • Gishu
    Gishu about 9 years
    @ViktorLexington - what if Bird already had to subclass Vertebrate ? Even if the language allows multiple inheritance - it usually results in a messier type design
  • Dariux
    Dariux almost 9 years
    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?
  • plalx
    plalx almost 9 years
    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?
  • plalx
    plalx almost 9 years
    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...
  • markus
    markus over 8 years
    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.
  • DavidRR
    DavidRR over 8 years
    @ybakos "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."
  • ybakos
    ybakos over 8 years
    @DavidRR 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.
  • Luaan
    Luaan over 8 years
    @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.
  • Radon Rosborough
    Radon Rosborough over 8 years
    @Luaan 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.
  • Luaan
    Luaan over 8 years
    @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).
  • Radon Rosborough
    Radon Rosborough over 8 years
    @Luaan 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.
  • Luaan
    Luaan over 8 years
    @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).
  • Radon Rosborough
    Radon Rosborough over 8 years
    @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.)
  • Dave Newton
    Dave Newton over 8 years
    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.
  • Fuhrmanator
    Fuhrmanator over 8 years
    @Jeshurun 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.
  • Salx
    Salx about 8 years
    The last paragraph in this post really clicked for me. Thank you.
  • Catalyst
    Catalyst about 8 years
    leading in with "This rule is a complete nonsense" is a little obtuse, try making the points the strong statement.
  • Scott Hannen
    Scott Hannen almost 8 years
    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.
  • SPB
    SPB over 7 years
    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.
  • almanegra
    almanegra over 7 years
    I think it doesn't answer the question
  • Ravindra babu
    Ravindra babu over 7 years
    You can have re-look at OP question. I have addressed : What trade-offs are there for each approach?
  • almanegra
    almanegra over 7 years
    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 another
  • Ravindra babu
    Ravindra babu over 7 years
    pros and cons provides trade-off since pros of inheritance is cons of composition and cons of composition is pros of inheritance.
  • iPherian
    iPherian about 7 years
    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.
  • iPherian
    iPherian about 7 years
    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.
  • iPherian
    iPherian about 7 years
    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.
  • Scott Hannen
    Scott Hannen about 7 years
    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.
  • Nick Bull
    Nick Bull over 6 years
    This doesn't answer the question. The question is "why" not "what".
  • Fuzzy Logic
    Fuzzy Logic over 5 years
    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.
  • Boris Dalstein
    Boris Dalstein over 5 years
    @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.
  • Boris Dalstein
    Boris Dalstein over 5 years
    @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.
  • Fuzzy Logic
    Fuzzy Logic over 5 years
    computeArea(Circle *c) { return pi * width * height / 4.0; } Now it's generic.
  • Boris Dalstein
    Boris Dalstein over 5 years
    @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.
  • Boris Dalstein
    Boris Dalstein over 5 years
    @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().
  • Fuzzy Logic
    Fuzzy Logic over 5 years
    I was just kidding :) My only bone was wedging the problem into the composition model but you cleared that up.
  • Boris Dalstein
    Boris Dalstein over 5 years
    @FuzzyLogic Ah, sorry, didn't get the sarcasm :)
  • rahulaga-msft
    rahulaga-msft over 5 years
    @Gishu 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 ?
  • kisai
    kisai almost 5 years
    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.
  • iono
    iono almost 5 years
    @Gishu 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?
  • neonblitzer
    neonblitzer about 4 years
    "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.
  • sdindiver
    sdindiver about 4 years
    @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.
  • Anzurio
    Anzurio almost 4 years
    @sdindiver 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.
  • adnanmuttaleb
    adnanmuttaleb almost 4 years
    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.
  • Clint
    Clint almost 4 years
    @Gishu 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.
  • Paramvir Singh Karwal
    Paramvir Singh Karwal almost 4 years
    In this particular case of aircraft I would definitely not recommend to 'change the engine on the fly'
  • Carlos Ribeiro
    Carlos Ribeiro over 3 years
    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.
  • Nate T
    Nate T over 3 years
    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.
  • Nate T
    Nate T over 3 years
    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.
  • Isaak Eriksson
    Isaak Eriksson about 3 years
    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!
  • Taylor Bird
    Taylor Bird almost 3 years
    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.
  • Aleksey F.
    Aleksey F. over 2 years
    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.
  • Nom1fan
    Nom1fan over 2 years
    You are awesome, loved this answer :)
  • Boris Dalstein
    Boris Dalstein over 2 years
    @Nom1fan Thanks, I'm glad the answer was helpful!
  • numan
    numan over 2 years
    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.
  • Scotty Jamison
    Scotty Jamison about 2 years
    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.
  • wlnirvana
    wlnirvana about 2 years
    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")
  • wlnirvana
    wlnirvana about 2 years
    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.
  • John
    John about 2 years
    @Gishu "** 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"?
  • Boris Dalstein
    Boris Dalstein about 2 years
    @wlnirvana 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.
  • Scotty Jamison
    Scotty Jamison about 2 years
    @neonblitzer 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".