I hear (and read on this site) a lot about "favour composition over inheritance".
But what is Compositon? I understand inheritance from the point of Person : Mammal : Animal, but I can't really see the definition of Compostion anywhere.. Can somebody fill me in?
Composition refers to combining simple types to make more complex ones. In your example, composition could be:
Animal:
Skin animalSkin
Organs animalOrgans
Mammal::Animal:
Hair/fur mammalFur
warm-blooded-based_cirulation_system heartAndStuff
Person::Mammal:
string firstName
string lastName
If you wanted to go totally composition (and get rid of all inheritance) it would look like this:
Animal:
Skin animalSkin
Organs animalOrgans
Mammal:
private Animal _animalRef
Hair/fur mammalFur
warm-blooded-based_cirulation_system heartAndStuff
Person:
private Mammal _mammalRef
string firstName
string lastName
The advantage to this approach is that the types Mammal and Person do not have to conform to the interface of their previous parent. This could be a good thing because sometimes a change to the superclass can have serious effects on the subclasses.
They still can have access to the properties and behaviours of these classes through their private instances of these classes, and if they want to expose these former-superclass behaviours, they can simply wrap them in a public method.
I found a good link with good examples here: http://www.artima.com/designtechniques/compoinh.html
Composition is simply the parts that make up the whole. A car has wheels, an engine, and seats. Inheritance is a "is a " relationship. Composition is a "has a" relationship.
There are three ways to give behavior to a class. You can write that behavior into the class; you can inherit from a class that has the desired behavior; or you can incorporate a class with the desired behavior into your class as a field, or member variable. The last two represent forms of code reuse, and the final one - composition - is generally preferred. It doesn't actually give your class the desired behavior - you still need to call the method on the field - but it puts fewer constraints on your class design and results in easier to test and easier to debug code. Inheritance has its place, but composition should be preferred.
class Engine
{
}
class Automobile
{
}
class Car extends Automobile // car "is a" automobile //inheritance here
{
Engine engine; // car "has a" engine //composition here
}
Composition - Functionality of an object is made up of an aggregate of different classes. In practice, this means holding a pointer to another class to which work is deferred.
Inheritance - Functionality of an object is made up of it's own functionality plus functionality from its parent classes.
As to why composition is preferred over inheritance, take a look at the Circle-ellipse problem.
An example of Composition is where you have an instance of a class within another class, instead of inheriting from it
This page has a good article explaining why people say "favour composition over inheritance" with some examples of why.
composition
simply mean using instance variables that are references to other objects.
For an illustration of how inheritance compares to composition in the code reuse department, consider this very simple example:
1- Code via inheritance
class Fruit {
// Return int number of pieces of peel that
// resulted from the peeling activity.
public int peel() {
System.out.println("Peeling is appealing.");
return 1;
}
}
class Apple extends Fruit {
}
class Example1 {
public static void main(String[] args) {
Apple apple = new Apple();
int pieces = apple.peel();
}
}
When you run the Example1 application, it will print out "Peeling is appealing.", because Apple inherits (reuses) Fruit's implementation of peel(). If at some point in the future, however, you wish to change the return value of peel() to type Peel, you will break the code for Example1. Your change to Fruit breaks Example1's code even though Example1 uses Apple directly and never explicitly mentions Fruit.
for more info ref
Here's what that would look like:
class Peel {
private int peelCount;
public Peel(int peelCount) {
this.peelCount = peelCount;
}
public int getPeelCount() {
return peelCount;
}
//...
}
class Fruit {
// Return a Peel object that
// results from the peeling activity.
public Peel peel() {
System.out.println("Peeling is appealing.");
return new Peel(1);
}
}
// Apple still compiles and works fine
class Apple extends Fruit {
}
// This old implementation of Example1
// is broken and won't compile.
class Example1 {
public static void main(String[] args) {
Apple apple = new Apple();
int pieces = apple.peel();
}
}
2- Code via composition
Composition provides an alternative way for Apple to reuse Fruit's implementation of peel(). Instead of extending Fruit, Apple can hold a reference to a Fruit instance and define its own peel() method that simply invokes peel() on the Fruit. Here's the code:
class Fruit {
// Return int number of pieces of peel that
// resulted from the peeling activity.
public int peel() {
System.out.println("Peeling is appealing.");
return 1;
}
}
class Apple {
private Fruit fruit = new Fruit();
public int peel() {
return fruit.peel();
}
}
class Example2 {
public static void main(String[] args) {
Apple apple = new Apple();
int pieces = apple.peel();
}
}
for more information ref
Related
I have an interface, say IVehicle, which is implemented in 100s of classes, some of them are variety of 4 wheeler and some are two wheeler dervied types.
I need to introduce a new method for all the 4 wheeler classes, lets say there are 50 of them. My challenge is to reduce the effort as much as I can.
I suggested, to introduce a new interface / abstract class with a method definition. But this require to change every 4 wheeler class declaration and extend with an extra parent.
Is there any possible way?
If you really want to avoid changing all those classes and want a solution that can be considered to be OO, one thing you can do is decorate those classes where they are used and need this extra behaviour.
I'll use C# for example code as you mentioned you're looking for C#/Java solution.
interface IVehicle
{
void DoThisNormalThing();
// ...
}
interface IBetterVehicle : IVehicle
{
void DoThisNeatThing();
}
class FourWheelVehicle : IVehicle
{
public void DoThisNormalThing()
{
// ...
}
// ...
}
class BetterFourWheelVehicle : IBetterVehicle
{
private readonly _vehicle;
public BetterFourWheelVehicle(IVehicle vehicle)
{
_vehicle = vehicle;
}
public void DoThisNormalThing()
{
_vehicle.DoThisNormalThing();
}
public void DoThisNeatThing()
{
// ...
}
// ...
}
Then usage:
var vehicle = new FourWheelVehicle();
var betterVehicle = new BetterFourWheelVehicle(vehicle);
betterVehicle.DoThisNeatThing();
This can be done using extension methods as well (and would result in a little less code and fewer allocated objects), but as this question is tagged with [oop] I wouldn't say extension methods are an OO construct. They're much more aligned with procedural style as they turn your objects into bags of procedures.
Why does object's type refer to its interface? Why the term type is used here? In terms of C++ I am not able to understand it.
Gamma, Erich. Design Patterns: Elements of Reusable Object-Oriented
Software (Addison-Wesley Professional Computing Series) (Kindle
Locations 593-596). Pearson Education. Kindle Edition.
An object’s class defines how the object is implemented. The class
defines the object’s internal state and the implementation of its
operations. In contrast, an object’s type only refers to its
interface—the set of requests to which it can respond. An object can
have many types, and objects of different classes can have the same
type.
An oversimplification...
Interface - a list of things that a class have and the things that it can do... a list of things that answer the "Whats"
Implementation - answers the question on "How" the "Whats" are accomplished.
Example:
An interface IPackageMover that does 2 things and 2 classes (types) that actually implements the interface (and also do other things aside from the interface requires)
// the interface
public interface IPackageMover
{
string GetName();
void public void MoveTo(Package package, string newAddress);
}
// the "type" that has the implementation
public class JoeThePackageMover : IPackageMover
{
public string GetName()
{
return "Joe";
}
public void MoveTo(Package package, string newAddress)
{
PickUp(package);
Drive(newAddress);
DropOff(package);
}
public void PickUp(Package package)
{
// do stuff
}
public void Drive(string newAddress)
{
// do stuff
}
public void DropOff(Package package)
{
// do stuff
}
}
// another "type" with the same interface
public class PassTheBuckPackageMover : IPackageMover
{
public string GetName()
{
return "What do you want it to be?";
}
public void MoveTo(Package package, string newAddress)
{
var joe = new JoeThePackageMover();
joe.MoveTo(package, newAddress);
}
public void Chill()
{
//do stuff
}
}
Why does object's type refer to its interface? Why the term type is used here? In terms of C++ I am not able to understand it.
Objects in OOP are not very different from the real world. For example :
A Car IS-A Vehicle. By this definition, a Car has the ability to transport people/cargo from one place to another.
A Car is also a Car. By this definition, it has the ability to be driven using a steering wheel.
In the above example, a Car IS-A Car and a Car is also a Vehicle because it can be driven using a steering wheel to move cargo/people from one place to another. In other words, the type of an object in the real world is defined by the things you can do with it (vis-à-vis it's interface.)
If we use the above analogy in programming, Car is a subclass of Vehicle and code that has a Car object can use all functions from Vehicle as well as Car. This would mean that a Car IS-A Vehicle and a Car. In conclusion, the type of object is defined by its interface, i.e the set of operations it supports.
Referring to the below link:
http://www.javaworld.com/javaworld/jw-11-1998/jw-11-techniques.html?page=2
The composition approach to code reuse provides stronger encapsulation
than inheritance, because a change to a back-end class needn't break
any code that relies only on the front-end class. For example,
changing the return type of Fruit's peel() method from the previous
example doesn't force a change in Apple's interface and therefore
needn't break Example2's code.
Surely if you change the return type of peel() (see code below) this means getPeelCount() wouldn't be able to return an int any more? Wouldn't you have to change the interface, or get a compiler error otherwise?
class Fruit {
// Return int number of pieces of peel that
// resulted from the peeling activity.
public int peel() {
System.out.println("Peeling is appealing.");
return 1;
}
}
class Apple {
private Fruit fruit = new Fruit();
public int peel() {
return fruit.peel();
}
}
class Example2 {
public static void main(String[] args) {
Apple apple = new Apple();
int pieces = apple.peel();
}
}
With a composition, changing the class Fruit doesn't necessary require you to change Apple, for example, let's change peel to return a double instead :
class Fruit {
// Return String number of pieces of peel that
// resulted from the peeling activity.
public double peel() {
System.out.println("Peeling is appealing.");
return 1.0;
}
}
Now, the class Apple will warn about a lost of precision, but your Example2 class will be just fine, because a composition is more "loose" and a change in a composed element does not break the composing class API. In our case example, just change Apple like so :
class Apple {
private Fruit fruit = new Fruit();
public int peel() {
return (int) fruit.peel();
}
}
Whereas if Apple inherited from Fruit (class Apple extends Fruit), you would not only get an error about an incompatible return type method, but you'd also get a compilation error in Example2.
** Edit **
Lets start this over and give a "real world" example of composition vs inheritance. Note that a composition is not limited to this example and there are more use case where you can use the pattern.
Example 1 : inheritance
An application draw shapes into a canvas. The application does not need to know which shapes it has to draw and the implementation lies in the concrete class inheriting the abstract class or interface. However, the application knows what and how many different concrete shapes it can create, thus adding or removing concrete shapes requires some refactoring in the application.
interface Shape {
public void draw(Graphics g);
}
class Box implement Shape {
...
public void draw(Graphics g) { ... }
}
class Ellipse implements Shape {
...
public void draw(Graphics g) { ... }
}
class ShapeCanvas extends JPanel {
private List<Shape> shapes;
...
protected void paintComponent(Graphics g) {
for (Shape s : shapes) { s.draw(g); }
}
}
Example 2 : Composition
An application is using a native library to process some data. The actual library implementation may or may not be known, and may or may not change in the future. A public interface is thus created and the actual implementation is determined at run-time. For example :
interface DataProcessorAdapter {
...
public Result process(Data data);
}
class DataProcessor {
private DataProcessorAdapter adapter;
public DataProcessor() {
try {
adapter = DataProcessorManager.createAdapter();
} catch (Exception e) {
throw new RuntimeException("Could not load processor adapter");
}
}
public Object process(Object data) {
return adapter.process(data);
}
}
static class DataProcessorManager {
static public DataProcessorAdapter createAdapter() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
String adapterClassName = /* load class name from resource bundle */;
Class<?> adapterClass = Class.forName(adapterClassName);
DataProcessorAdapter adapter = (DataProcessorAdapter) adapterClass.newInstance();
//...
return adapter;
}
}
So, as you can see, the composition may offer some advantage over inheritance in the sense that it allows more flexibility in the code. It allows the application to have a solid API while the underlaying implementation may still change during it's life cycle. Composition can significantly reduce the cost of maintenance if properly used.
For example, when implementing test cases with JUnit for Exemple 2, you may want to use a dummy processor and would setup the DataProcessorManager to return such adapter, while using a "real" adapter (perhaps OS dependent) in production without changing the application source code. Using inheritance, you would most likely hack something up, or perhaps write a lot more initialization test code.
As you can see, compisition and inheritance differ in many aspects and are not preferred over another; each depend on the problem at hand. You could even mix inheritance and composition, for example :
static interface IShape {
public void draw(Graphics g);
}
static class Shape implements IShape {
private IShape shape;
public Shape(Class<? extends IShape> shape) throws InstantiationException, IllegalAccessException {
this.shape = (IShape) shape.newInstance();
}
public void draw(Graphics g) {
System.out.print("Drawing shape : ");
shape.draw(g);
}
}
static class Box implements IShape {
#Override
public void draw(Graphics g) {
System.out.println("Box");
}
}
static class Ellipse implements IShape {
#Override
public void draw(Graphics g) {
System.out.println("Ellipse");
}
}
static public void main(String...args) throws InstantiationException, IllegalAccessException {
IShape box = new Shape(Box.class);
IShape ellipse = new Shape(Ellipse.class);
box.draw(null);
ellipse.draw(null);
}
Granted, this last example is not clean (meaning, avoid it), but it shows how composition can be used.
Bottom line is that both examples, DataProcessor and Shape are "solid" classes, and their API should not change. However, the adapter classes may change and if they do, these changes should only affect their composing container, thus limit the maintenance to only these classes and not the entire application, as opposed to Example 1 where any change require more changes throughout the application. It all depends how flexible your application needs to be.
If you would change Fruit.peel()'s return type, you would have to modify Apple.peel() as well. But you don't have to change Apple's interface.
Remember: The interface are only the method names and their signatures, NOT the implementation.
Say you'd change Fruit.peel() to return a boolean instead of a int. Then, you could still let Apple.peel() return an int. So: The interface of Apple stays the same but Fruit's changed.
If you would have use inheritance, that would not be possible: Since Fruit.peel() now returns a boolean, Apple.peel() has to return an boolean, too. So: All code that uses Apple.peel() has to be changed, too. In the composition example, ONLY Apple.peel()'s code has to be changed.
The key word in the sentence is "interface".
You'll almost always need to change the Apple class in some way to accomodate the new return type of Fruit.peel, but you don't need to change its public interface if you use composition rather than inheritance.
If Apple is a Fruit (ie, inheritance) then any change to the public interface of Fruit necessitates a change to the public interface of Apple too. If Apple has a Fruit (ie, composition) then you get to decide how to accomodate any changes to the Fruit class; you're not forced to change your public interface if you don't want to.
Return type of Fruit.peel() is being changed from int to Peel. This doesn't meant that the return type of Apple.peel() is being forced to change to Peel as well. In case of inheritance, it is forced and any client using Apple has to be changed. In case of composition, Apple.peel() still returns an integer, by calling the Peel.getPeelCount() getter and hence the client need not be changed and hence Apple's interface is not changed ( or being forced to be changed)
Well, in the composition case, Apple.peel()'s implementation needs to be updated, but its method signature can stay the same. And that means the client code (which uses Apple) does not have to be modified, retested, and redeployed.
This is in contrast to inheritance, where a change in Fruit.peel()'s method signature would require changes all way into the client code.
I'm trying to find a good example for the use of multiple inheritance what cannot be done with normal interfaces.
I think it's pretty hard to find such an example which cannot be modeled in another way.
Edit: I mean, can someone name me a good real-world example of when you NEED to use multiple inheritance to implement this example as clean as possible. And it should not make use of multiple interfaces, just the way you can inherit multiple classes in C++.
The following is a classic:
class Animal {
public:
virtual void eat();
};
class Mammal : public Animal {
public:
virtual void breathe();
};
class WingedAnimal : public Animal {
public:
virtual void flap();
};
// A bat is a winged mammal
class Bat : public Mammal, public WingedAnimal {
};
Source: wiki.
One example where multiple class inheritance makes sense is the Observer pattern. This pattern describes two actors, the observer and the observable, and the former wants to be notified when the latter changes its object state.
A simplified version for notifying clients can look like this in C#:
public abstract class Observable
{
private readonly List<IObserver> _observers = new List<IObserver>();
// Objects that want to be notified when something changes in
// the observable can call this method
public void Subscribe(IObserver observer)
{
_observers.Add(observer);
}
// Subclasses can call this method when something changes
// to notify all observers
protected void Notify()
{
foreach (var observer in _observers)
observer.Notify();
}
}
This basically is the core logic you need to notify all the registered observers. You could make any class observable by deriving from this class, but as C# does only support single class inheritance, you are limited to not derive from another class. Something like this wouldn't work:
public class ImportantBaseClass { /* Members */ }
public class MyObservableSubclass : ImportantBaseClass, Observable { /* Members */ }
In these cases you often have to replicate the code that makes subclasses observable in all of them, basically violating the Don't Repeat Yourself and the Single Point of Truth principles (if you did MVVM in C#, think about it: how often did you implement the INotifyPropertyChanged interface?). A solution with multiple class inheritance would be much cleaner in my opinion. In C++, the above example would compile just fine.
Uncle Bob wrote an interesting article about this, that is where I got the example from. But this problem often applies to all interfaces that are *able (e.g. comparable, equatable, enumerable, etc.): a multiple class inheritance version is often cleaner in these cases, as stated by Bertrand Meyer in his book "Object-Oriented Software Construction".
I am new to OOP. Though I understand what polymorphism is, but I can't get the real use of it. I can have functions with different name. Why should I try to implement polymorphism in my application.
Classic answer: Imagine a base class Shape. It exposes a GetArea method. Imagine a Square class and a Rectangle class, and a Circle class. Instead of creating separate GetSquareArea, GetRectangleArea and GetCircleArea methods, you get to implement just one method in each of the derived classes. You don't have to know which exact subclass of Shape you use, you just call GetArea and you get your result, independent of which concrete type is it.
Have a look at this code:
#include <iostream>
using namespace std;
class Shape
{
public:
virtual float GetArea() = 0;
};
class Rectangle : public Shape
{
public:
Rectangle(float a) { this->a = a; }
float GetArea() { return a * a; }
private:
float a;
};
class Circle : public Shape
{
public:
Circle(float r) { this->r = r; }
float GetArea() { return 3.14f * r * r; }
private:
float r;
};
int main()
{
Shape *a = new Circle(1.0f);
Shape *b = new Rectangle(1.0f);
cout << a->GetArea() << endl;
cout << b->GetArea() << endl;
}
An important thing to notice here is - you don't have to know the exact type of the class you're using, just the base type, and you will get the right result. This is very useful in more complex systems as well.
Have fun learning!
Have you ever added two integers with +, and then later added an integer to a floating-point number with +?
Have you ever logged x.toString() to help you debug something?
I think you probably already appreciate polymorphism, just without knowing the name.
In a strictly typed language, polymorphism is important in order to have a list/collection/array of objects of different types. This is because lists/arrays are themselves typed to contain only objects of the correct type.
Imagine for example we have the following:
// the following is pseudocode M'kay:
class apple;
class banana;
class kitchenKnife;
apple foo;
banana bar;
kitchenKnife bat;
apple *shoppingList = [foo, bar, bat]; // this is illegal because bar and bat is
// not of type apple.
To solve this:
class groceries;
class apple inherits groceries;
class banana inherits groceries;
class kitchenKnife inherits groceries;
apple foo;
banana bar;
kitchenKnife bat;
groceries *shoppingList = [foo, bar, bat]; // this is OK
Also it makes processing the list of items more straightforward. Say for example all groceries implements the method price(), processing this is easy:
int total = 0;
foreach (item in shoppingList) {
total += item.price();
}
These two features are the core of what polymorphism does.
Advantage of polymorphism is client code doesn't need to care about the actual implementation of a method.
Take look at the following example.
Here CarBuilder doesn't know anything about ProduceCar().Once it is given a list of cars (CarsToProduceList) it will produce all the necessary cars accordingly.
class CarBase
{
public virtual void ProduceCar()
{
Console.WriteLine("don't know how to produce");
}
}
class CarToyota : CarBase
{
public override void ProduceCar()
{
Console.WriteLine("Producing Toyota Car ");
}
}
class CarBmw : CarBase
{
public override void ProduceCar()
{
Console.WriteLine("Producing Bmw Car");
}
}
class CarUnknown : CarBase { }
class CarBuilder
{
public List<CarBase> CarsToProduceList { get; set; }
public void ProduceCars()
{
if (null != CarsToProduceList)
{
foreach (CarBase car in CarsToProduceList)
{
car.ProduceCar();// doesn't know how to produce
}
}
}
}
class Program
{
static void Main(string[] args)
{
CarBuilder carbuilder = new CarBuilder();
carbuilder.CarsToProduceList = new List<CarBase>() { new CarBmw(), new CarToyota(), new CarUnknown() };
carbuilder.ProduceCars();
}
}
Polymorphism is the foundation of Object Oriented Programming. It means that one object can be have as another project. So how does on object can become other, its possible through following
Inheritance
Overriding/Implementing parent Class behavior
Runtime Object binding
One of the main advantage of it is switch implementations. Lets say you are coding an application which needs to talk to a database. And you happen to define a class which does this database operation for you and its expected to do certain operations such as Add, Delete, Modify. You know that database can be implemented in many ways, it could be talking to file system or a RDBM server such as MySQL etc. So you as programmer, would define an interface that you could use, such as...
public interface DBOperation {
public void addEmployee(Employee newEmployee);
public void modifyEmployee(int id, Employee newInfo);
public void deleteEmployee(int id);
}
Now you may have multiple implementations, lets say we have one for RDBMS and other for direct file-system
public class DBOperation_RDBMS implements DBOperation
// implements DBOperation above stating that you intend to implement all
// methods in DBOperation
public void addEmployee(Employee newEmployee) {
// here I would get JDBC (Java's Interface to RDBMS) handle
// add an entry into database table.
}
public void modifyEmployee(int id, Employee newInfo) {
// here I use JDBC handle to modify employee, and id to index to employee
}
public void deleteEmployee(int id) {
// here I would use JDBC handle to delete an entry
}
}
Lets have File System database implementation
public class DBOperation_FileSystem implements DBOperation
public void addEmployee(Employee newEmployee) {
// here I would Create a file and add a Employee record in to it
}
public void modifyEmployee(int id, Employee newInfo) {
// here I would open file, search for record and change values
}
public void deleteEmployee(int id) {
// here I search entry by id, and delete the record
}
}
Lets see how main can switch between the two
public class Main {
public static void main(String[] args) throws Exception {
Employee emp = new Employee();
... set employee information
DBOperation dboper = null;
// declare your db operation object, not there is no instance
// associated with it
if(args[0].equals("use_rdbms")) {
dboper = new DBOperation_RDBMS();
// here conditionally, i.e when first argument to program is
// use_rdbms, we instantiate RDBM implementation and associate
// with variable dboper, which delcared as DBOperation.
// this is where runtime binding of polymorphism kicks in
// JVM is allowing this assignment because DBOperation_RDBMS
// has a "is a" relationship with DBOperation.
} else if(args[0].equals("use_fs")) {
dboper = new DBOperation_FileSystem();
// similarly here conditionally we assign a different instance.
} else {
throw new RuntimeException("Dont know which implemnation to use");
}
dboper.addEmployee(emp);
// now dboper is refering to one of the implementation
// based on the if conditions above
// by this point JVM knows dboper variable is associated with
// 'a' implemenation, and it will call appropriate method
}
}
You can use polymorphism concept in many places, one praticle example would be: lets you are writing image decorer, and you need to support the whole bunch of images such as jpg, tif, png etc. So your application will define an interface and work on it directly. And you would have some runtime binding of various implementations for each of jpg, tif, pgn etc.
One other important use is, if you are using java, most of the time you would work on List interface, so that you can use ArrayList today or some other interface as your application grows or its needs change.
Polymorphism allows you to write code that uses objects. You can then later create new classes that your existing code can use with no modification.
For example, suppose you have a function Lib2Groc(vehicle) that directs a vehicle from the library to the grocery store. It needs to tell vehicles to turn left, so it can call TurnLeft() on the vehicle object among other things. Then if someone later invents a new vehicle, like a hovercraft, it can be used by Lib2Groc with no modification.
I guess sometimes objects are dynamically called. You are not sure whether the object would be a triangle, square etc in a classic shape poly. example.
So, to leave all such things behind, we just call the function of derived class and assume the one of the dynamic class will be called.
You wouldn't care if its a sqaure, triangle or rectangle. You just care about the area. Hence the getArea method will be called depending upon the dynamic object passed.
One of the most significant benefit that you get from polymorphic operations is ability to expand.
You can use same operations and not changing existing interfaces and implementations only because you faced necessity for some new stuff.
All that we want from polymorphism - is simplify our design decision and make our design more extensible and elegant.
You should also draw attention to Open-Closed Principle (http://en.wikipedia.org/wiki/Open/closed_principle) and for SOLID (http://en.wikipedia.org/wiki/Solid_%28Object_Oriented_Design%29) that can help you to understand key OO principles.
P.S. I think you are talking about "Dynamic polymorphism" (http://en.wikipedia.org/wiki/Dynamic_polymorphism), because there are such thing like "Static polymorphism" (http://en.wikipedia.org/wiki/Template_metaprogramming#Static_polymorphism).
You don't need polymorphism.
Until you do.
Then its friggen awesome.
Simple answer that you'll deal with lots of times:
Somebody needs to go through a collection of stuff. Let's say they ask for a collection of type MySpecializedCollectionOfAwesome. But you've been dealing with your instances of Awesome as List. So, now, you're going to have to create an instance of MSCOA and fill it with every instance of Awesome you have in your List<T>. Big pain in the butt, right?
Well, if they asked for an IEnumerable<Awesome>, you could hand them one of MANY collections of Awesome. You could hand them an array (Awesome[]) or a List (List<Awesome>) or an observable collection of Awesome or ANYTHING ELSE you keep your Awesome in that implements IEnumerable<T>.
The power of polymorphism lets you be type safe, yet be flexible enough that you can use an instance many many different ways without creating tons of code that specifically handles this type or that type.
Tabbed Applications
A good application to me is generic buttons (for all tabs) within a tabbed-application - even the browser we are using it is implementing Polymorphism as it doesn't know the tab we are using at the compile-time (within the code in other words). Its always determined at the Run-time (right now! when we are using the browser.)