This question already has answers here:
Prefer composition over inheritance?
(35 answers)
Closed 2 years ago.
I was going through the difference between inheritance and composition. Everyone has praised composition over inheritance, so questions is how do we make choice ? Also if we didn't use inheritance at all then what are we going to miss as per OOP principal ?
It really comes down to how your data is structured. Inheritance is used for "is a" relationships while composition is used for "has a" relationships.
For example, if you were look at cars.
Inheritance: you would have 'Toyota', 'Honda', 'BMW' under 'Car' because they are types of cars.
Composition: you would have 'Engine', 'Wheels', 'Door' under 'Car' because they are parts that make up the car.
'Toyota', 'Honda', 'BMW' aren't parts of a car same way 'Engine', 'Wheels', 'Door' aren't types of cars.
This is a big complicated topic, perhaps too much to be described in a few SO posts.
Inheritance can be tricky, People have done Ph.D dissertations on this. Most of the time when I write new code I keep inheritance to a minimum.
When your Dog class inherits Mammal all the state/behavior of Mammal must still apply.
(the dog is a mammal). Is a platypus a mammal? Biology-yes, but it may not apply to your needs. Especially when you have mutable objects you run into
messy situations such as https://en.wikipedia.org/wiki/Circle%E2%80%93ellipse_problem#Description
Also in real life there's often goofy couplings between parent and child classes.
You cannot say that one should be preferred over another. It depends how the data is structured and what representation is required for a particular data model. There is a simple way to remember what to use:
Inheritance = is
The fact an object inherits from another means the object actually is what it inherits from, hierarchically. Let's take an example from the simplified taxonomy in biology. Working with the kingdom Animalia, we can say that Opossum is a Mammal, which is Chordate, which is animal. Therefor here we have a chain of the inheritance: Opossum extends Mammal, Mammal extends Chordate, Chordate extends Animal. Each of the group has various characteristics that all the subtypes inherit.
Composition = has
The composition is has. However, here this relation should be rather understood as is composed from or contains. If we stay in the world of biology, we can say an Opossum has a head, tail, body and 4 legs, therefore there is a composition relationship between these objects. This is in Java represented as instance fields:
class Opossum {
Head head;
Body body;
Leg[] legs = new Legs[4];
}
You can google thousands articles about it. So if you want to understand more deeply, google and learn, we dont have to reinvent wheel here.
If you want short explanation what composition over inheritance means, it basically says - do not overengineer your solution with some super complex inheritance. If you develop something and you see some clear advantages of inheritance and you cant achieve the same with composition, you are free to use inheritance. If you dont see it or you can achieve the same with composition, use composition.
Related
I'm trying to get my head around design patterns. I think they may be one step too advanced in my programming abilities as I am struggling quite a bit with them, however my university assignment is to apply them. So here I am.
I am going through the example of the Decorator Pattern from the Head First book. This is the example:
As you can see in the diagram, the CondimentDecorator has the IS-A and HAS-A relationship with Beverage. However, here is the code they write for the CondimentDecorator and one of the condiments, Mocha:
In the CondimentDecorator class the only thing that it contains is a method getDescription.
It's the Mocha class that contains instantiates the Beverage class AND calls getDescription.
So doesn't this mean that it's the Mocha class that has a IS-A and a HAS-A relationship?
The decorator pattern is indeed not easy to grasp when learning OOP: it uses inheritance and object composition together to offer something that looks like dynamic inheritance but is mostly based on composition. In addition, the example uses several levels of inheritance, which makes it even more complex to grasp.
The idea in this design, is twofold:
a Mocha is a CondimentDecorator that you can use it everywhere where a CondimentDecorator is expected. Moreover, since a CondimentDecorator is a Beverage, you can also use a Mocha everywhere where a Beverage is expected. This is the purpose of the inheritance in this design (IS-A).
a CondimentDecorator object (such as a particular Mocha) knows a Beverage object that it enriches with additional responsibilities, acting as intermediary: it deals a "front-end" to the external world, and enriches the behavior of the other objects by doing additional things in addition to forwarding calls. This is the purpose of the association which is implemented in a code with object composition (i.e. Beverage beverage) - (HAS-A, but this terminology might be misleading).
In consequence, we can observe the following:
The Mocha class inherits the HAS-A and the IS-A relationships from the CondimentDecorator. These inherited relationships are not added in the UML diagram.
The Mocha class has no additional HAS-A relationship
The Mocha class must implement its own getDescription() , since it inherits directly from the CondimentDecorator which makes it abstract, whereas the Beverage provides a default implementation.
An instance of Mocha, e.g. an object Mocha aMochaInCup2987662 = new Mocha(aHouseBlendInCup2987662); is itself at the same time a Beverage a CondimentDecorator and a Mocha and has internally all the features provided by the three classes even if they are not all visible/accessible.
I'm playing around with subclassing vs Interfaces and composition. I end up getting confused about a few things when it comes to the code duplication. As we all know there are alot of scenarios where subclassing and inheritance is just not the way to go, however it's effective in terms of reducing code duplication.
Interfaces are strong and gives great readability if done properly but i cant wrap my head around the fact that it's really not helping me with the reducing of code duplicaton. We can end up in scenarios where subclassing is not effective.. But the possibilities to extend the program is big and whenever we do so, trying to maintain the Open closed principal, we end up doing Realizations / Implementations of Interfaces in absurd amounts of copy paste code, where it's probably avoidable with subclassing (in terms of code duplication).
How do we build up great strategies with Interfaces and Composition where we avoid writing the same methods over and over again? In such a way that we can keep the modularity and stick with the open closed principle at the same time. Do we have any guidelines to how we can fast and effective decide if the code duplication in fact will be worth it in the end?
Cheers
< /wallOfText>
Object Oriented modelling is very subjective, but the only thing I can thing of here is the old Inheritance vs. Composition discussion:
https://www.thoughtworks.com/insights/blog/composition-vs-inheritance-how-choose
Based on your argumentation, I believe you often tries to extract a superclass from two or more classes with similar code, so they can all share the same inherited methods instead of just duplicate them. Although technically this gives you exactly what you want, you should also take care of the inheritance semantics since it will denote an is-a relationship (i.e., car is-a vehicle, dog is-a mammal, report-screen is-a read-only-screen). Since Java doesn't offer multiple inheritance, you may end up limited and confused if you class hierarchy grows.
So, before start extracting superclasses for reuse, have in mind that you can also extract this code-i-want-to-reuse units to be part-of other classes (composition).
Sorry for my conceptual example, but here it goes:
Both Dog and Lion are mammals and hunters. They should naturally inherit Mammals superclass (with a lot of reusable code among mammals). As not all mammals hunt, we don't want to define a new hunt() method on Mammals class.
At this very point, you may be thinking of creating a new inheritance level: Mammals <- HuntingMammals. But think: if you continue doing this for every distinctive aspect of animals, you'll have dozens of classes in a tricky and puzzled hierarchy. Besides that, we also know that some reptiles and birds also hunt, so, we'd better isolate all the hunting thing elsewhere.
As a healthy alternative to inheritance, we can define a separate Hunter class. To reuse it's contents, all we need to do is put a Hunter object as member of both Dog and Lion (a field). If we need to treat dogs and lions as hunters together (polymorphically), we can define a CanHunt interface to group them.
Check the example below:
class Hunter {
void hunt(){
System.out.println("i'm hunting...");
}
}
interface CanHunt{
Hunter getHunter();
}
class Dog extends Mammals implements CanHunt{
...
Hunter hunter = new Hunter();
#Override
Hunter getHunter(){
return hunter;
}
...
}
class Lion extends Mammals implements CanHunt{
...
Hunter hunter = new Hunter();
#Override
Hunter getHunter(){
return hunter;
}
...
}
And here we have a polymorphic sample code that ask both dog and lion to do their hunting stuff:
...
List<CanHunt> hunters = new LinkedList();
hunters.add(new Dog());
hunters.add(new Lion());
for(CanHunt h:hunters){
h.getHunter().hunt(); //we don't know if it's a dog or a lion here...
}
...
I hope this simple example gives you some inspiration. And it can get quite complex if we keep evolving it towards a more detailed though flexbile design. For instance, Hunter class could be abstract with different implementations, since dog hunts differentlty from lions, but they share some common behaviour.
I find this question quite interesting as most of us don't have enough time to read and re-read all the classes we could inherit and that could lead us to write very inefficient code and sometimes to "reinvent the wheel" which in the end would cost us more time than if we've taken a look at other classes.
My suggestion to solve this problem is to create microservices, small mini-apps that perform special pieces of work, that way you wouldn't have to use inheritance as much as now and you'll know the exact output you're getting. Furthermore, you would be able to re-use those "microservices" in other apps.
As a side note, check the books suggested by #AntoineDubuis I found they would be very helpful.
As I see it visitor design pattern is very similar to the way composition work.
In composition I would hold an interface member in the class and pass a concrete implementation of the interface in the constructor, and then either delegate a method to it or use it inside the class.
In visitor design pattern I also have a concrete implementation of the interface, and I send it to the visit method which then delegates the visit method to it.
To show this similarity in code, a visitor would be:
VisitorInterface v = new ConcreteVisitor();
MyClass c = new MyClass();
c.visit(v);
VisitorInterface dv = new DifferentVisitor();
c.visit(dv);
And composition would be:
SomeInterface i = new ConcreteImplementation();
MyClass c = new MyClass(i);
c.visit(); // called visit just to show the symmetry to visitor pattern
SomeInterface di = new DifferentImplementation();
c.changeReference(di);
c.visit();
I would like to hear your thoughts as to in which cases you would prefer one over the other and why
Composition is the means of expressing a has-a relationship between objects, in other words, to model attributes of an object. A cow has horns. Injection is not essential to this. The Visitor pattern is a way to perform an external action on a type. They serve different purposes and operate on different portions of the object model. To answer your question, I prefer composition when the logic of the situation calls for a type to have an attribute, and the Visitor pattern to organize code to perform an action on instances of a type without altering the structure of the target type, as documented for that pattern.
"Visitor design pattern is very similar to the way composition work."
It is actually not. Composition is a basic principle for object creation like Abstraction, Encapsulation, Polymorphism etc. It is simply a has-a relationship. Adapter, Composite and Decorator patterns are perfect examples for utilizing Composition principle.
Visitor pattern is rather a high level solution deduced from basic programming principles. The basic logic behind Visitor is method-overloading based on different sub-class types.
Ex: You have a base-class or interface named Bird and sub classes Crow, Duck and Penguin. And you want a method of some client class to act different w.r.t. the type of the sub-class. i.e. here assume, I want a Hunter class which differentiates the behavior of Hunter.hunt() method w.r.t. whether it is Crow, Duck or Penguin.
So my Hunter class looks like this.
public class Hunter{
public void hunt(Crow crow){
//crow hunting logic.
}
public void hunt(Duck duck){
//duck hunting logic.
}
public void hunt(Penguin penguin){
//penguin hunting logic.
}
}
And if I do like this,
Bird bird = new Duck();
Hunter hunter = new Hunter();
hunter.hunt(bird);
Now this hunter.hunt(); will automatically navigate into hunt(Duck duck) method and get executed.
I think you understood that there's no much relationship between composition principle and visitor pattern.
And as a final note, Visitor is not a good pattern in general. The reason is, it makes you keep overloading more and more methods when different new sub-classes are getting added. In our example if you want to add new classes like Pigeon, Eagle etc., you will have to add methods hunt(Pigeon pigeon) and hunt(Eagle eagle). This would be a terrible maintenance issue in large scale especially. So it would be better, if you use it only if there's no other option or no bouncing back.
maybe you should think where you can use mentioned patterns in order to understand the difference:
Composite:
Compose objects into tree structures to represent part-whole hierarchies.Group of objects is to be treated in the same way as a single instance of an object.
Drawing example(swing library from java):a drawing may be composed(composites) of graphic primitives, such as lines, circles, rectangles, text, and so on. But in order to draw we manipulate composites exactly the same way we manipulate primitive objects.
Visitor:
Allows for one or more operations to be applied to a set of objects at runtime, decoupling the operations from object structure.
Basic idea is to have same mechanism how to walk through object structure(object structure can be tree and that looks similar to Composite) and then on each step via objects in structure we can have one or more operations,
in compilers AST is object struture and visitor can be used to walk via AST and generate binary code, or XML output or ...
hope that this helps
Most design patten books say we should "Favor object composition over class inheritance."
But can anyone give me an example that inheritance is better than object composition.
Inheritance is appropriate for is-a relationships. It is a poor fit for has-a relationships.
Since most relationships between classes/components fall into the has-a bucket (for example, a Car class is likely not a HashMap, but it may have a HashMap), it then follows the composition is often a better idea for modeling relationships between classes rather than inheritance.
This is not to say however that inheritance is not useful or not the correct solution for some scenarios.
My simple answer is that you should use inheritance for behavioral purposes. Subclasses should override methods to change the behaviour of the method and the object itself.
This article (interview with Erich Gamma, one of the GoF) elaborates clearly why Favor object composition over class inheritance.
In Java, whenever you inherit from a class, your new class also automatically becomes a subtype of the original class type. Since it is a subtype, it needs to adhere to the Liskov substitution principle.
This principle basically says that you must be able to use the subtype anywhere where the supertype is expected. This severely limits how the behavior of your new inherited class can differ from the original class.
No compiler will be able to make you adhere to this principle though, but you can get in trouble if you don't, especially when other programmers are using your classes.
In languages that allow subclassing without subtyping (like the CZ language), the rule "Favor object composition over inheritance" is not as important as in languages like Java or C#.
Inheritance allows an object of the derived type to be used in nearly any circumstance where one would use an object of the base type. Composition does not allow this. Use inheritance when such substitution is required, and composition when it is not.
Just think of it as having an "is-a" or a "has-a" relationship
In this example Human "is-a" Animal, and it may inherits different data from the Animal class. Therefore Inheritance is used:
abstract class Animal {
private String name;
public String getName(){
return name;
}
abstract int getLegCount();
}
class Dog extends Animal{
public int getLegCount(){
return 4;
}
}
class Human extends Animal{
public int getLegCount(){
return 2;
}
}
Composition makes sense if one object is the owner of another object. Like a Human object owning a Dog object. So in the following example a Human object "has-a" Dog object
class Dog{
private String name;
}
class Human{
private Dog pet;
}
hope that helped...
It is a fundamental design principle of a good OOD. You can assign a behaviour to a class dynamicly "in runtime", if you use composition in your design rather than inheritance like in Strategy Pattern. Say,
interface Xable {
doSomething();
}
class Aable implements Xable { doSomething() { /* behave like A */ } }
class Bable implements Xable { doSomething() { /* behave like B */ } }
class Bar {
Xable ability;
public void setAbility(XAble a) { ability = a; }
public void behave() {
ability.doSomething();
}
}
/*now we can set our ability in runtime dynamicly */
/*somewhere in your code */
Bar bar = new Bar();
bar.setAbility( new Aable() );
bar.behave(); /* behaves like A*/
bar.setAbility( new Bable() );
bar.behave(); /* behaves like B*/
if you did use inheritance, the "Bar" would get the behaviour "staticly" over inheritance.
Inheritance is necessary for subtyping. Consider:
class Base {
void Foo() { /* ... */ }
void Bar() { /* ... */ }
}
class Composed {
void Foo() { mBase.Foo(); }
void Bar() { mBase.Foo(); }
private Base mBase;
}
Even though Composed supports all of the methods of Foo it cannot be passed to a function that expects a value of type Foo:
void TakeBase(Base b) { /* ... */ }
TakeBase(new Composed()); // ERROR
So, if you want polymorphism, you need inheritance (or its cousin interface implementation).
This is a great question. One I've been asking for years, at conferences, in videos, in blog posts. I've heard all kinds of answers. The only good answer I've heard is preformance:
Performance differences in languages. Sometimes, classes take advantage of built-in engine optimizations that dynamic compositions don't. Most of the time, this is a much smaller concern than the problems associated with class inheritance, and usually, you can inline everything you need for that performance optimization into a single class and wrap a factory function around it and get the benefits you need without a problematic class hierarchy.
You should never worry about this unless you detect a problem. Then you should profile and test differences in perf to make informed tradeoffs as needed. Often, there are other performance optimizations available that don't involve class inheritance, including tricks like inlining, method delegation, memoizing pure functions, etc... Perf will vary depending on the specific application and language engine. Profiling is essential, here.
Additionally, I've heard lots of common misconceptions. The most common is confusion about type systems:
Conflating types with classes (there are a couple existing answers concentrate on that here already). Compositions can satisfy polymorphism requirements by implementing interfaces. Classes and types are orthogonal, though in most class-supporting languages, subclasses automatically implement the superclass interface, so it can seem convenient.
There are three very good reasons to avoid class inheritance, and the crop up again and again:
The gorilla/banana problem
"I think the lack of reusability comes in object-oriented languages, not functional languages. Because the problem with object-oriented languages is they’ve got all this implicit environment that they carry around with them. You wanted a banana but what you got was a gorilla holding the banana and the entire jungle." ~ Joe Armstrong, quoted in "Coders at Work" by Peter Seibel.
This problem basically refers to the lack of selective code reuse in class inheritance. Composition lets you select just the pieces you need by approaching software design from a "small, reusable parts" approach rather than building monolithic designs that encapsulate everything related to some given functionality.
The fragile base class problem
Class inheritance is the tightest coupling available in object-oriented design, because the base class becomes part of the implementation of the child classes. This is why you'll also hear the advice from the Gang of Four's "Design Patterns" classic: "Program to an interface, not an implementation."
The problem with implementation inheritance is that even the smallest change to the inner details of that implementation could potentially break child classes. If the interface is public, exposed to user-land in any way, it could break code you are not even aware of.
This is the reason that class hierarchies become brittle -- hard to change as you grow them with new use-cases.
The common refrain is that we should be constantly refactoring our code (see Martin Fowler et al on extreme programming, agile, etc...). The key to refactor success is that you can't break things -- but as we've just seen, it's difficult to refactor a class hierarchy without breaking things.
The reason is that it's impossible to create the correct class hierarchy without knowing everything you need to know about the use-cases, but you can't know that in evolving software. Use cases get added or changed in projects all the time.
There is also a discovery process in programming, where you discover the right design as you implement the code and learn more about what works and what doesn't. But with class inheritance, once you get a class taxonomy going, you've painted yourself into a corner.
You need to know the information before you start the implementation, but part of learning the information you need involves building the implementation. It's a catch-22.
The duplication by necessity problem. This is where the death spiral really gets going. Sometimes, you really just want a banana, not the gorilla holding the banana, and the entire jungle. So you copy and paste it. Now there's a bug in a banana, so you fix it. Later, you get the same bug report and close it. "I already fixed that". And then you get the same bug report again. And again. Uh-oh. It's not fixed. You forgot the other banana! Google "copy pasta".
Other times, you really need to work a new use-case into your software, but you can't change the original base class, so instead, you copy and paste the entire class hierarchy into a new one and rename all the classes you need in the hierarchy to force that new use-case into the code base. 6 months later a new dev is looking at the code and wondering which class hierarchy to inherit from and nobody can provide a good answer.
Duplication by necessity leads to copy pasta messes, and pretty soon people start throwing around the word "rewrite" like it's no big deal. The problem with that is that most rewrite projects fail. I can name several orgs off the top of my head that are currently maintaining two development teams instead of one while they work on a rewrite project. I've seen such orgs cut funding to one or the other, and I've seen projects like that chew through so much cash that a startup or small business runs out of money and shuts down.
Developers underestimate the impact of class inheritance all the time. It's an important choice, and you need to be aware of the trade offs you opt into every time you create or inherit from a base class.
I'm working on a homework assignment (a project), for which one criterion is that I must make use of polymorphism in a way which noticeably improves the overall quality or functionality of my code.
I made a Hash Table which looks like this:
public class HashTable<E extends Hashable>{
...
}
where Hashable is an interface I made that has a hash() function.
I know that using generics this way improves the quality of my code, since now HashTable can work with pretty much any type I want (instead of just ints or Strings for example). But I'm not sure if it demonstrates polymorphism.
I think it does, because E can be any type that implements Hashable. In other words HashTable is a class which can work with (practically) any type.
But I'm not quite sure - is that polymorphism? Perhaps can I get some clarification as to what exactly polymorphism is?
Thanks in advance!
Edit: After receiving the answer below (see: first answer received), I read the Wikipedia article, and came across this:
"In the object-oriented programming community, programming using parametric polymorphism is often called generic programming." (emphasis added)
Polymorphism is, in a nutshell, taking many different classes which share a common base class (or interface), and treating them all as members of that common base, without knowing or caring which particular inheriting class they are or how precisely they implement the common functions. In object oriented programming, polymorphism gives you a relatively high-level view of that part of your problem domain - you're saying, "This code doesn't care about the specific details of these objects - just that they implement some common functions X,Y,Z," or "just that they're all of the basic class BaseClass."
Your example uses polymorphism, because you define a Hashable base class - and provide a function that cares only about that aspect of the objects it receives. Hashable objects may have many forms, but your code treats them all as a single basic type.
Yes, it's called parametric polymorphism. Your reasoning for classing it as polymorphism is spot-on.
In addition to parametric polymorphism, you'll presumably be calling the hashCode method of objects stored in the hash table, which is an example of the polymorphism John refers to. HashTable relies on parametric polymorphism, and E relies on (plain) polymorphism.
While Rob's answer might be true in some technical sense, I don't think it's what is being asked for. I think this wikipedia article is more likely to be what you need.