When I design classes and have to choose between inheritance and composition, I usually use the rule of thumb: if the relationship is "is-a" - use inheritance, and if the relationship is "has-a" - use composition.
Is it always right?
Thank you.
When I design classes and have to choose between inheritance and composition, I usually use the rule of thumb: if the relationship is "is-a" - use inheritance, and if the relationship is "has-a" - use composition.
Is it always right?
Thank you.
NoYes. If the relationship is "has-a", use composition. (Added: the original version of question said "use inheritance" for both - a simple typo, but the correction alters the first word of my answer from "No" to "Yes".)
And use composition by default; only use inheritance when necessary (but then don't hesitate to use it).
Yes and no.
The line can be blurred. This hasn't been helped by some pretty terrible examples of OO programming from the early days of OO like: Manager is an Employee is a Person.
The thing you have to remember about inheritance is: inheritance breaks encapsulation. Inheritance is an implementation detail. There's all sorts written on this subject.
The pithiest way to sum it up is:
Prefer composition.
That doesn't mean use it to the complete exclusion of inheritance. It just means inheritance is a fallback position.
I don't think it's as simple as "is-a" vs "has-a" - as cletus said, the line can get very blurry. It's not like two people would always come to the same conclusion given just that as a guideline.
Also as cletus said, prefer composition over inheritance. To my mind, there have to be really good reasons to derive from a base class - and in particular, the base class really needs to have been designed for inheritance, and indeed for the kind of specialization you want to apply.
Beyond that - and this will probably be an unpopular idea - it comes down to taste and gut feeling. Over time I think good developers get a better sense of when inheritance will work and when it won't, but they may well find it hard to express clearly. I know I find it hard, as this answer demonstrates. Maybe I'm just projecting the difficulty onto other people though :)
Inheritance doesn't always mean there is an "is-a" relationship and the lack of one doesn't always mean there isn't.
Examples:
What i'm trying to say here is it takes a lot of thought and work to maintain an "is-a" substitutable relationship between two types whether you use inheritance or not.
People often say that inheritance is an "is-a" relationship, but that can get you into trouble. Inheritance in C++ splits into two ideas: code reuse and defining interfaces.
The first says "My class is like this other class. I'll just write code for the delta between them and reuse the other implementation from the other class as much as I can."
The second depends on abstract base classes and is a list of methods the class promises to implement.
The first can be very handy, but it can also cause maintenance problems if not done well and so some people will go so far as saying you should never do it. Most people emphasize the second, using inheritance for what other languages explicitly call an interface.
My rule of thumb (though not concrete) is that if I can use the same code for different classes, then I put that code into a parent class and use inheritance. Otherwise I use composition.
This causes me to write less code which is inherently easier to maintain.
If the relationship is "is-a" - use inheritance, and if the relationship is "has-a" - use composition. Is it always right?
In a sense, yes. But you must be careful not to introduce unnecessary, artificial "is-a" relationships.
For example, one may think that a ThickBorderedRectangle is-a Rectangle, which seems reasonable at first sight, and decide to use inheritance. But this situation is better described saying that a Rectangle has-a Border, which may or may not be a ThickBorder. In this case he would better prefer composition.
In the same fashion, one may think that a ThickBorder is-a special Border and use inheritance; but it's better to say that a Border has-a width, hence preferring composition.
In all these ambiguous cases, my rules of thumb are think twice and, as others advised, prefer composition over inheritance.
No - "is a" does not always lead to inheritence. A well cited example is the relationship between a square and a rectangle. A square is a rectangle, but it will be bad to design code that inherits a Square class off a Rectangle class.
My suggestion is to enhance your "is a / has a" heuristic with the Liskov Substitution Principle. To check whether an inheritence relationship complies with the Liskov Substitution Principle, ask whether clients of a base class can operate on the sub class without knowing that it is operating on a sub class. Of course, all the properties of the sub class must be preserved.
In the square / rectangle example, we must ask whether a client of rectangle can operate on a square without knowing that it is a square. All that the client must know is that it is operating on a rectangle. The following function demonstrates a client that assumes that setting the width of a rectangle leaves the height unchanged.
void g(Rectangle& r)
{
r.SetWidth(5);
r.SetHeight(4);
assert(r.GetWidth() * r.GetHeight()) == 20);
}
This assumption is true for a rectangle, but not for a square. So the function cannot operate on a square and therefore the inheritence relationship violates the Liskov Substitution principle. (By the way - the example came from the linked article.)
I think John has the right Idea. Your looking at your class relationships as creating model which is what they try to get you to do when they start teaching you OOP principals. Really, your better off looking at how things function in terms the codes architecture. That is, whats the best way for other programmers (or yourself) to re-use your code without breaking it or having to look at the implementation to see what it does.
I've found that inheritance often breaks the "black box" ideal, so if information hiding is important it may not be the best way to go. I've found increasingly that inheritance is better for providing a common interface than it is for re-using components in other places.
Of course every situation is unique, and there is no correct way to make this decision, only rules of thumb.