Polymorphism vs Strategy pattern - java

What is the difference between the Strategy pattern and Polymorphism in Java?
I'm confused that whatever is achieved via Strategy Pattern is basically possible by polymorphism. Correct me if I'm wrong in this regard.
Please, also provide me example to eradicate my confusion.

For me, the link from CKing post and the example in Wikipedia are clear enough, but I'll try to give you a new example. As they said, Strategy Pattern is mostly a way to change the behaviour of an algorithm at runtime. Of course you can achieve this in many different ways (such as holding a value and using switch-case, but it wouldn't be as nice as Strategy Pattern).
Let's say you're developing a turn-based strategy game with two kind of Units: Infantry and Tank (subclasses of Unit). Your terrain could be Plains, Railroad or Forests.
class Unit{
MovementStrategy ms;
final int baseMovement;
int x,y;
public Unit(int baseMovement){
this.baseMovement = baseMovement;
}
abstract void fire();
void moveForward(){
x = x + ms.getHexagonsToMove(baseMovement);
}
void setMovementStrategy(MovementStrategy ms){
this.ms = ms;
}
}
Any Unit subclass must implement fire() method because it's going to be completely different for them (Tank shots heavy long-distance round and Infantry shot several short distance light bullets). In this example we use normal polymorphism/inheritance since fire() method will be really different for any unit, and it won't change during the game.
class Infantry extends Unit{
public Infantry(){
super(2);
}
void fire(){
//whatever
}
}
class Tank extends Unit{
public Tank(){
super(5);
}
void fire(){
//whatever
}
}
Units also are able to move, and have a field baseMovement that holds the number of hexagons it can walk. We're developing a strategy game, not a real world simulation, so we don't care how they move, we just want to add a value to their coordinates (in my example I only use X coordinate in order to get a simpler code). If all the terrain was the same, we wouldn't need any Strategy object... but we need to change the behaviour of move() method at runtime!
So, we implement a different MovementStrategy class for each of our kinds of Terrain, and we program our game to trigger a setMovementStrategy() to any unit that move on each hexagon. And we don't even need to write anything else in our Unit subclasses.
interface MovementStrategy{
public int getHexagonsToMove(int base);
}
class PlainMovementStrategy implements MovementStrategy{
public int getHexagonsToMove(int base){
return base;
}
}
class RailroadMovementStrategy implements MovementStrategy{
public int getHexagonsToMove(int base){
return base*3;
}
}
class ForestMovementStrategy implements MovementStrategy{
public int getHexagonsToMove(int base){
return (int)(base/2);
}
}
Now, when any Unit move inside a Forest, we call
unit.setMovementStrategy(new ForestMovementStrategy());
And as soon it goes to a Plain, we do:
unit.setMovementStrategy(new PlainMovementStrategy());
Now we're able to change how far away our units move depending on the Terrain, and we don't need to rewrite in any of the subclasses.
I hope this helps you a better understanding of the difference.

I'm confused that whatever is achieved via Strategy Pattern is basically possible by polymorphism.
You can't drive a car without a steering wheel. That does not mean that a steering wheel is a car. Similarly, the Strategy pattern relies on polymorphism but that does not mean that they are the same thing.
The purpose of the Strategy pattern is to promote the use of composition (has-a) over inheritance (is-a). Instead of your class inheriting behavior from a super class, you define the behavior in a separate class and your class has-a reference to it.
As far as an example goes, take a look at this answer that does a good job.

Basic difference : Polymorphism is programming language concept, and Strategy pattern is one of behavioral design pattern of GoF.
Polymorphism is the provision of a single interface for several different underlying data types.
Example: The steering wheel(i.e., the interface) is same no matter what type of actual steering mechanism is used. That is, the steering wheel works the same whether your car has manual steering, power steering, or rack-and-pinion steering. Therefore once you know how to operate the steering wheel, you can drive any type of car.
In programming, Polymorphism implemented in two ways:
Early-Binding/Static/Compile-Time Polymorphism (ex: function overloading)
Late-Binding/Dynamic/Run-Time Polymorphism (ex: function overriding)
A Strategy pattern defines a set of algorithms that can be used interchangeably.
The Strategy pattern is a dynamic pattern (How do you want run a behavior in software?).
Example of core java: java.util.Comparator#compare(), executed by among others Collections#sort().
Modes of transportation is analogous to strategy design pattern. We use car, bike, bus, local train and so on.. different strategies to go office day by day.

If you are establishing an analogy where:
in one case you have several overridable methods;
in the other case you have a Strategy interface with several implementations,
then the difference is the degree of coupling, which is very strong in the first case, whereas in the second case any foreign code can participate in your class's logic by contributing its Strategy implementation.

Q: What is the difference between the Strategy pattern and Polymorphism
in Java?
The questions is certainly confusing since initially there seems not to be any relation between these two ideas.
Polymorphism is a much broader concept in programming and yes the strategy pattern in Java uses a form of polymorphism catalogued as inclusion polymorphism to accomplish its intent, but this is by no means the only type of polymorphism that exists, neither it is the only way to implement the strategy pattern as I will demonstrate soon.
Also polymorphism is not something that only exists in Java or in object-oriented programming languages. Different forms of polymorphism exist in all the programming paradigms and not in all languages you are forced to use polymorphism to implement a strategy pattern (e.g. functional languages).
For further discussion on this topic please read this other answer where we have discussed whether polymorphism is possible without inheritance and I provide interesting references and examples to other types of polymorphism like parametric and ad-hoc polymorphism.
Ideally this will reveal to you that polymorphism is a bigger concept that goes beyond the boundaries of object-oriented programming and even beyond inheritance and subtyping.
Q: I'm confused that whatever is achieved via Strategy Pattern is
basically possible by polymorphism. Correct me if I'm wrong in this
regard.
From my point of view the relations between these two concepts are: that the strategy pattern leverages the power of polymorphism available in languages like Java to implement its intent, and that polymorphism can be considered in itself a pattern.
For instance, consider this quote from the GoF book:
If we assumed procedural languages, we might have included design
patterns called 'inheritance', 'encapsulation' and 'polymorphism'.
It is just that we rarely think of polymorphism as a pattern, first because it implies many things and because it is implemented differently in different languages and also because it typically presents as some form of language feature.
In his book Elemental Design Patterns, Jason Mc C. Smith comments on the GoF quote above saying:
Pattern are language-independent concepts; they take form and become
concrete solutions when you implement them within a particular
language with a given set of language features and constructs [...]
This means that it is a bit strange to talk about "Java design
pattern", "C++ design patterns", "Websphere design pattern" and so on,
even though we all do it. It's a mildly lazy form of shorthand for
what we really mean, or should mean: design patterns as implemented in
Java, C++, WebSphere and so on, regardless of language or API.
So, as you can see, you are thinking in the Strategy pattern from the perspective of the Java implementation, but in other language paradigms such pattern may have been implemented in different ways, probably without using inheritance at all, for example, in pure functional programming languages this is most certainly implemented using high order functions and function composition.
As such, this would be an strategy pattern implementation without resorting to inclusion polymorphism at all. In a function composition strategy we may still be using other forms of polymorphism (e.g. parametric), but that is not a requirement for the strategy pattern
Q: Please, also provide me example to eradicate my confusion.
As discussed above, in Java we are probably forced to use inclusion polymorphism to implement a Strategy pattern, but as explained above as well, patterns are not something that belong to a specific language, so if we think of the strategy pattern as a concept living outside any language boundaries then you will easily see other languages implement this in different ways.
In some hypothetical functional language I may have a function that reads some data from a file, maybe the file is encrypted and you need to provide a decryption strategy:
function readFile(path: String, decrypt: string -> string) {
return decrypt(loadFromDisk(path));
}
And that decrypt argument is a function that serves the purpose of a strategy pattern, it encapsulates an interchangeable algorithm.
Now you can do
readFile("customers.txt", aes)
readFile("finance.txt", blowfish)
Where aes and blowfish are decryption function strategies.
There are dozens of languages that work like this, SML, Haskell, JavaScript, etc.

First of all. Polymorphism can mean two different things. Most commonly polymorphism refers to a polymorphic type. However, you are asking for the pattern.
Polymorphic code can change itself each time it runs while the function of the code stays the same. An easy example is to do 1+3=4 instead of 5-1=4. Both achieves the same result using different code. This is useful for code that does not want to be recognized i.e computer viruses or cryptographic code.
Strategy pattern on the other hand uses a family of algorithms that can be interchanged. This might be used when translating text. First some code determines the language. if the language is swedish or spanish the text will be processed by, different functions of the same family, translateSwedish() or translateSpanish().
To round things up. Polymorphic code uses different code that achieves the same result. While Strategy uses different code to achieve better results.

Consider this
we have animals and a strategy pattern object to describe how they move...
for instance
fly/swim/walk
Given the large number of animals that use any of these methods (ie thousands of different animals fly), we need to use the same code for many different animals. That code should only exist in one place, so that it is easily changed and doesn't take up any unneeded space.
In this example, a straightforward polymorphism approach will result in massive code duplication. A more complex approach which places a intermediate class between animal and say robin fail to take in to consideration that how a animal moves is not really what defines it. Furthermore, it is possible that a animal has other strategy objects and they cannot all be made polymorphic through intermediate classes.

One definition for Polymorphism is the provision of a single interface to entities of different types.
With that in mind say you have a “bird” interface and all of your bird classes must implement “laysEggs()” method, well no biggie that works. And as you keep coding your “bird paradise program” you now add the “fly()” and realize that overloading and overriding for penguin and kiwi is unnecessary as in real life they can't fly, yet you must still implement that method. This can become tedious and pointless as you are faced with Ostrich and others that can't fly. And even worst off when adding the method “swim()” because even fewer birds can swim. As you may already know, the strategy pattern solves this problem.
In lame-man’s terms you can think of Polymorphism as a conglomerate of practices, while the Strategy Pattern is the best practice for a specific case. Example: the Strategy Pattern is to be used when an algorithm's behavior needs to be selected at Runtime (via interchangeable algorithms). And although it is sort of true that whatever is achieved via Strategy Pattern is basically possible by polymorphism, without knowledge of the Strategy Pattern this would leave you with the “reinvent the wheel” problem to solve this specific problem. In conclusion, they are very different even if one is based on the other.
I'll leave you to see “Ender Muab'Dib” code as it is well explained if you still want a code example from me just ask, cheers and hope I helped.

Polymorphism is a principle and Strategy is a design pattern
From oracle documentation page
The dictionary definition of polymorphism refers to a principle in biology in which an organism or species can have many different forms or stages. This principle can also be applied to object-oriented programming and languages like the Java language. Subclasses of a class can define their own unique behaviors and yet share some of the same functionality of the parent class.
Polymorphism can be achieved in compile time ( method overloading) and run time (method overriding).
Strategy_pattern
Defines a family of algorithms,
Encapsulates each algorithm, and
Makes the algorithms interchangeable within that family.
Strategy can use run-time polymorphism principle to achieve the desired functionality.
Strategy pattern had one more component called Context in it's URL diagram.
Refer to below SE posts:
Real World Example of the Strategy Pattern
Does this Java Strategy pattern have a redundant Context class?
Few more useful articles:
strategy by sourcemaking

Here is the concise response:
Polymorphism is one of the fundamental characteristics of
object-oriented programming.
Strategy pattern is a language-independent pattern that can be implemented by all
programming languages paradigms, such as imperative, functional, and
object-oriented.
Therefore, if you are going to implement Strategy pattern by using Java, that is OOP, then you just need to use polymorphism.
In other words, Strategy pattern is one of many forms of polymorphism.

Related

Visitor vs Composition

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

How to distinguish between design patterns and standard polymorphism

For example I have one interface and a bunch of classes as follows
public interface Drawable{
void draw(); // draws something on screen for example.
}
abstract class Shape implements Drawable {...}
class Circle extends Shape{...} // assume that draw() is implemented in both classes.
class Square extends Shape{...} // ...
Now if I have a main class and perform the following:
class Main{
Shape s1 = new Circle();
s1.draw(); // assume that this will draw a circle.
s1 = new Square();
s1.draw(); //assume that this will draw a square.
}
I'm I using a design pattern here? or is this just standard polymorphism? If this is a design pattern then what is it called?
In my opinion, a design pattern is a tried-and-tested manner of writing code to solve a problem. The way in which you employ a given design pattern could significantly differ depending on the programming language you use.
Design patterns are rarely supported at the language level (although newer languages like Groovy do implement particular design patterns at the language-level; for example, the "Method Object" pattern is provided in Groovy using a language level feature called "Closures").
The code you've given is an example of Polymorphism, which is one of the fundamental concepts of OOP. Polymorphism is, however, one of the foundations for implementing many design patterns.
Polymorphism is supported at the language-level; it is not something that you can code into your program.
There was a Java book written in 1998, still available at Amazon which in Chapter 4, called out "Inteface", "Abstract Superclass" and other things as "Fundamental Design Patterns."
This claim was somewhat controversial, as many people would say these are just basic mechanisms rather than "design patterns."
Short answer is: people will give you both answers, though in my experience, most people would say no.

How does the Visitor Pattern not violate the Open/Closed Principle?

From Wikipedia :
The idea was that once completed, the implementation of a class could only be modified to
correct errors; new or changed features would require that a different class be created.
That class could reuse coding from the original class through inheritance
From what I understand, The Visitor pattern is a powerful technique to traverse similar but different objects that implement the same Interface by the use of double dispatch. In one of my Java examples, I created a composite set of objects that form a tree structure, and each specific implementation of those objects implement the visitable interface. The visitor interface has a method for each of the visitable objects, and the concrete visitor implements what to do for each of those cases.
The thing I'm trying to get my head around is the fact that if I were to add a new implementation to the composite structure that also implements visitable, then I need to reopen the visitor interface and add that case to it, also forcing me to modify each implementation of visitor.
While this is fine, since I would need to do this anyway (What good is adding to your visitables if the visitor can't understand them?) but on an academic level, wouldn't this be violating the Open Closed Principle? Isn't that one of the core reasons for Design Patterns anyway? Trying to show a decent reason for switching to this pattern instead of maintaining a switch statement to end all switch statements, but everyone argues that the code will be the same anyways, with a method for each case instead of a switch block, just broken up and harder to read.
A pattern is applicable to certain cases. From the GoF book (p. 333):
Use the Visitor pattern when
[...]
the classes defining the object structure rarely change, but you often want to define new operations over the structure. Changing the
object structure classes requires redefining the interface to all
visitors, which is potentially costly. If the object structure classes
change often, then it's probably better to define the operations in
those classes.
If you frequently change the classes of the objects that make up the structure, the Visitor class hierarchy can be hard to maintain. In such a case, it may be easier to define operations on the classes that make up the structure.
John Vlissides, one of the GoF, wrote an excellent chapter on the subject in his Patterns Hatching book. He discusses the very concern that extending the hierarchy is incompatible with maintaining the visitor intact. His solution is a hybrid between a visitor and an enum-based (or a type-based) approach, where a visitor is provided with a visitOther method called by all classes outside the "base" hierarchy that the visitor understands out of the box. This method provides you an escape way to treat the classes added to the hierarchy after the visitor has been finalized.
abstract class Visitable {
void accept(Visitor v);
}
class VisitableSubclassA extends Visitable {
void accept(Visitor v) {
v.visitA(this);
}
}
class VisitableSubclassB extends Visitable {
void accept(Visitor v) {
v.visitB(this);
}
}
interface Visitor {
// The "boilerplate" visitor
void visitB(VisitableSubclassA a);
void visitB(VisitableSubclassB b);
// The "escape clause" for all other types
void visitOther(Visitable other);
}
When you add this modification, your visitor is no longer in violation of the Open-Close Principle, because it is open to extension without the need to modify its source code.
I tried this hybrid method on several projects, and it worked reasonably fine. My main class hierarchy is defined in a separately compiled library which does not need to change. When I add new implementations of Visitable, I modify my Visitor implementations to expect these new classes in their visitOther methods. Since both the visitors and the extending classes are located in the same library, this approach works very well.
P.S. There is another article called Visitor Revisited discussing precisely that question. The author concludes that one can go back to an enum-based double dispatch, because the original Visitor Pattern does not present a significant improvement over the enum-based dispatch. I disagree with the author, because in cases when the bulk of your inheritance hierarchy is solid, and the users are expected to provide a few implementations here and there, a hybrid approach provides significant benefits in readability; there is no point in throwing out everything because of a couple of classes that we can fit into the hierarchy with relative ease.
The first two answers are great. To expand on the observation, "A pattern is applicable to certain cases," consider OCP in two dimensions.
Object-oriented code is open for extension when we can add new types to an existing hierarchy. We cannot add new functions to the existing types.
Functional code is open for extension when we can add new logic to existing data structures. We cannot pass new data structures through existing functions.
This dichotomy is called the expression problem. The Visitor Pattern allows us to trade the usual dimension in which OO is extensible, and in return we gain the dimension in which FP is extensible.
To reconcile Visitor with OCP, we might say the pattern simply opens a different dimension for extensibility. A tradeoff in the dimensions of extensibility is applicable to certain cases.

Disadvantage of object composition over class inheritance

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.

Is generic programming an example of polymorphism?

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.

Categories

Resources