7

This post is based on the question https://stackoverflow.com/questions/49002/prefer-composition-over-inheritance/11758048#comment15634305_11758048.

Some people said - check whether there is “is-a” relationship. If it is there use inheritance. What I think is there should be a second check for using inheritance. Use inheritance only if the base class is abstract. If the base class need to be instantiated then use composition; not inheritance.

E.g 1. Accountant is an Employee. But I will not use inheritance because a Employee object can be instantiated. (When you talk to business people, they will tell you - Accountant is an Employee. But in OO world Accountant is not (should not be) an employee)

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

What I am looking for here is an example that will challenge my argument –that is a scenario in which inheritance is better than composition even though the base class is non-abstract (base class can be instantiated). Can you please provide such an example?

Note: It would be more helpful if you can provide a scenario based on Bank domain, HR domain, Retail domain or any other popular domain.

Note: In the design, please assume that we have full control of the code. That is we are not using any external API. Also we are starting from beginning.

I will mark as answered if there is an example that explains a scenario that proves my argument is wrong. It is not a mere discussion on whether to use Composition or Inheritance.

I support @anon answer in https://stackoverflow.com/questions/3351666/why-use-inheritance-at-all?lq=1

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 Code Smell: Inheritance Abuse

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

interface (for polymorphism)

implementation (for code reuse)

REFERENCE

  1. Employee- Accountant Example https://stackoverflow.com/questions/11759120/issue-in-using-composition-for-is-a-relationship
  2. Selling Item Example - https://codereview.stackexchange.com/questions/14077/is-it-proper-tpt-inheritance
  3. Programming SOLID Principles
  4. Code Smell: Inheritance Abuse
8
  • 3
    Good question. However, the dog example it is wrong IMHO. A dog is an abstract term. It is always some concrete dog, you can not instantiate 'a dog'. It's always a poodle, a German shepherd, or some crossbreed. In this case, I'd say inheritance is the best, and most appropriate way to go. Commented Aug 2, 2012 at 9:33
  • @VainFellowman Thanks - I removed the poodle-dog example. I have upvoted your comment too..
    – LCJ
    Commented Aug 2, 2012 at 9:39
  • 1
    @Lijo: Your "Accountant is an Employee" is a poor example too! As per your accepted answer in the question you link to in ref #1: stackoverflow.com/a/11759272/213727 Commented Aug 2, 2012 at 10:02
  • 3
    I'm not so sure about your first example. If you made Employee a superclass of Accountant then that would imply that someone who starts as an accountant will always be an accountant. Employee roles is often used as an archetypal example of roles. The Employee is not the job title, but has the job title. As they change departments, get promoted, etc, the title associated with the employee changes, making Accountant a role that an employee can take on and discard
    – GordonM
    Commented Aug 2, 2012 at 13:42
  • 1
    @GordonM The question requires us to infer quite a bit. There's no question that employees change roles, but there's also no reason that you can't start representing an employee with a different class when their role changes unless we're talking about very long-lived objects such as records in a database.
    – Caleb
    Commented Aug 3, 2012 at 8:25

7 Answers 7

3

Although you mentioned in a comment it's not the talk about "composition vs inheritance", I have to return to it. Because composition is better than inheritance If we assume that decoupling is always a good thing (Prefer composition to inheritance?).

Actually it is not always the case. Even if you see that "is a" can be replaced with "has a" or "has a" looks more promising, "is a" has a very nice automatic properties.

Consider any widget hierarchy. Usually everything related to dimension is buried deep at the root. And no matter how long the inheritance path, you can always directly call SetBounds of the instance and pass the instance to a procedure that expects deep base object, the compiler will accept it because from "is a" comes automatic type conversion and access.

But if you convert the inheritance hierarchy into composition hierarchy (technically it is always possible), you will lose convenience in both cases, because you should point to the concrete piece of composition tree in order to change the dimension or provide a procedure with particular class type. Compare

 MyForm.SetBounds(...  // easy because of an "is a"-tree
 MyForm.ScrollingWinControl.WinControl.Control.SetBounds  //complex because of a "has a"-tree 

or

 GetSomeInfoOfControl(MyForm) // easy ...
 GetSomeInfoOfControl(MyForm.ScrollingWinControl.WinControl.Control) //complex ...

So despite the price of stronger coupling, inheritance sometimes is much easy to manage and abstract.

2
  • Thanks for the example. I prefer to replace the word "sometimes" with "on very rare occasions" in the sentence "So despite the price of stronger coupling, inheritance sometimes is much easy to manage and abstract."
    – LCJ
    Commented Aug 3, 2012 at 6:54
  • 1
    @Lijo, maybe you're right, the problem is that personally I'm not aware of a big library based solely on composition to see how it works. Are you?
    – Maksee
    Commented Aug 3, 2012 at 7:56
7

The entire 'is a' vs 'has a' discussion never made any sense to me. There is already a good definition about when to use inheritance, so called "Liskov substitution principle", which states:

Let q(x) be a property provable about objects x of type T. Then q(y) should be provable for objects y of type S where S is a subtype of T.

The first thing you'll notice is, that it is generally a bad idea to let people with PhD explain a simple problem.

Second, this exactly states when to use inheritance. If I may use Wikipedia's article and apply it to your accountant/employee example:

Liskov's notion of a behavioral subtype defines a notion of substitutability for mutable objects; that is, if Accountant is a subtype of Employee, then objects of type Employee in a program may be replaced with objects of type Accountant without altering any of the desirable properties of that program (e.g., correctness).

The entire Principles paragraph of the Wikipedia article contains some more interesting principles.


Apparently most answers refer to LSP in one way or the other. Baqueta cleverly disguised it as a easy-to-miss-link and Geek edited his post to include LSP seconds before I posted my answer. So, LSP seems to be the most reasonable way to create your hierarachy.


Some examples of where your principle doesn't hold:

In WPF, the concrete System.Windows.Controls.Button has the following subclasses:

In Java and C#, everything extends directly or indirectly from object, which isn't abstract.

Also in WPF: DatePickerTextBox is a subclass of (the concrete) TextBox. There are lots more examples. These respect LSP and the base class is not abstract.

As an extra note. I think the reason you found this principle is because it is generally a good idea to keep your hierarchy very flat, because inheritance introduces coupling. One or two levels deep is more than enough. Abstract classes will (almost) always be subclassed somewhere, since that is the purpose of making a class abstract, so that others can make it specialized. Most concrete classes don't need to be specialized in any way. That may be the reason you haven't found an example yet.

0
1

I think you've actually got there is a good rule of thumb for choosing to make a class abstract: if there are (or you can forsee the need for) variants of a class with slightly different behaviour, then it's often a good idea to create an abstract base class.

Bottom line though, in my experience: as long as the relationship you're dealing with is really is-a (e.g. your Accountant-Employee example is more suited to composition than inheritance, as per this answer) then it's very rarely harmful/problematic to inherit from non-abstract classes.

A couple of examples when you might want/have to ignore your rule. Both assume you require Poodle to be substitutable for Dog:

  1. Dog is a class in an external API and there's no IDog interface for Poodle to implement.
  2. Dog is already instantiated in dozens of different places in your (already tested) code.

Admittedly, these are both cases where a better original design might have helped, but in the real world designs are never perfect!

2
  • Thanks. The Dog-IDog issue comes due to external issues - like external API. Can you provide a scenario like - I have full control of all my classes - still inheritance can be better (with non-abstract base class). I am checking all possibilities :-)
    – LCJ
    Commented Aug 2, 2012 at 10:54
  • 1
    If you're designing from the ground up and have full control over the design, then I don't think I can come up with such a scenario: in that situation I think your rule is a pretty good one. I'm really saying that inheriting from a non-abstract class is not necessarily a bad thing. Commented Aug 2, 2012 at 11:11
1

I think inheriting concrete class is OK and actually quite valuable feature.

The "is-a" rule is only good for extremely simple models and domains. The way I see it, is that classes represent behavior and encapsulate state where the state can be another class. What kind of behavior Accountant, Employee, Book and Selling item have in relation to our model? That is the question you should ask. And based on that use either inheritance of composition.

Also, many real-world object are not good examples, because they are usually composites of different behaviors, that can be shared between different real-world objects. Many animal species walk on all 4. That is good example of behavior.

Extending already existing behavior by inheritance is great way to simplify and modularise the model of the domain. And for our walk behavior example, we can extend WoundedWalk class, that does exactly what its name says.

0
1

I don't think there is any necessity of a challenging example. What you say is a nice design principle which is named dependency inversion. That is, higher components should never depend on lower components. Lower components should depend on higher components only.

Like every rule, this one might have exceptions, too. But there are no rules without exceptions!

2
  • 1
    "Like every rule, this one might have exceptions, too. But there are no rules without exceptions!" -- If the second statement is true then you can change the tentative "might have" in the first statement to a definitive "will have", at which point you can remove the second statement :)
    – onedaywhen
    Commented Aug 23, 2012 at 8:34
  • @onedaywhen, I'd say "Who searched will find". But I wouldn't search in this case )))
    – superM
    Commented Aug 23, 2012 at 8:37
1

You use inheritance over composition when you need code reuse . Inheritance helps in evolving classes really fast . However , you should be careful not to overuse it . use it judiciously only when it makes sense (ie when you are absolutely sure that there is a "IS-A" relationship between every objects of both the classes .You need to make sure that the subclass objects respects the Liskov Substitution principle . Even then it might not be good idea everytime if you add a value component to a subclass and the super class also has the notion of a value component. From Effective Java :

There is no way to extend an instantiable class and add a value component while preserving the equals contract, unless you are willing to forgo the benefits of object-oriented abstraction.

On the other hand composition has multiple advantages over inheritance and so most of the times it is preferred over inheritance but that wasn't your question. Spring's *Dependency Injection principle * is primarily based on this premise .

0
1

What I am looking for here is an example that will challenge my argument

Examples abound:

  • Buttons. In many GUI frameworks, View is not an abstract class -- you can and often do create vanilla views. But there are also plenty of subclasses of View, such as Button.

  • Mutable objects. Some frameworks, e.g. Cocoa, have data container classes that are immutable (NSArray, NSString, NSDictionary, etc.) and also mutable subclasses of those (NSMutableArray, NSMutableString, etc.). You can do anything to an instance of NSMutableArray that you can do to an instance of NSArray, and then some.

  • Employee. Borrowing from your Accountant example, its likely that an Employee class might be a subclass of Person, but there's no reason that Person needs to be abstract.

  • Accountant. Your example is often given to illustrate how composition can/should be used in place of inheritance, but that doesn't mean that composition is always the best choice in this case. Yes, you can create an accountant by separating the 'job' aspects from the 'employee' and then configuring an instance of Employee with a particular job. But there may be good reasons to use inheritance instead. An accountant isn't just an employee who happens to crunch numbers; an accountant is a particular kind of employee, and you may want to use inheritance to reflect that. For example, you might want the Accountant class to implement a ProfessionalStanding interface or to include functionality that helps detect conflicts of interest. Also, creating an Accountant class makes it possible to use the language's type system to help prevent employees who aren't accountants from being used in roles where only an accountant should be used: Project::addAuditor(Accountant& a);

The decision to use or not use inheritance has little to do with whether a class is abstract. It's the other way around, actually: abstract classes are used to force you to create a subclass, generally to ensure that important missing functionality is provided. The fact that you can instantiate a class certainly doesn't mean that you should avoid subclassing.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.