Polymorphism is a simple concept that you understand right now, as it is prevalent through life. You are a person, which person is a base type and you are a more specific representation of that type. There are many people that inherit that type, of which you are a concrete implementation of that type: you have your own beliefs, attributes, and qualities that go beyond just a general person. For instance, we all have a blood type, shoe size, arm length, and many other properties. But we each add our own implementation to the person interface.
You drive an automobile, which this type has properties like wheel size, engine size, gas tank size, and other properties. The automobile you drive is a concrete implementation of the automobile interface. It has additional features, like sliding doors, logo type, cd changer slot count, moon roof lever location, or other various properties that are specific to the make/model of the car. In addition, automobile may have certain behaviors like open/close door, open trunk, turn wheel, and other behaviors that would be specific to an automobile.
In OO programming, using the automobile example, Automobile would be the base class, and each automobile manufacturer would have its own implementation. For instance, Honda has V-Tec technology, which is in its own implementation. Volvo uses diesel engines, which is the TDI technology. More importantly, you may add an added level of detail between automobile and the make/model implementation, such as Car, Truck, or Suv supertypes, to provide more relevant information.
Let's take a look at the automobile scenario. Here is an example automobile class:
Automobile class is the
interface, in that it defines an
interface that classes will derive from. You can't directly instantiate it through
new Automobile() because it's not an implementation; however, you can cast derived types to the
Automobile type. In this sense, it defines a common
interface across many derived implementations.
It's important to note the
BodyType property. This property is declared
abstract, meaning that any derived implementation must override it and return some relevant string (we will see more of this with the next class definitions). This is similar to the
Template Method pattern in that it exposes properties/methods that derived classes must override, but which
Automobile doesn't need to know anything about.
Automobile wants the derived class to return something relevant to it, but doesn't care what.
Now, from the example above, let's say we want a higher level of abstraction, in that there are varying types of
cars and we want to target that. It is possible for classes to inherit from
Automobile, but to also be an
interface in that it can't be directly instantiated, but any class can inherit additional properties/methods from it. Below are two such class definitions, for
BodyType method is overridden to return a
string that represents the type of body that's appropriate to the supertype. Also notice that
Suv also expose their own properties/methods, even abstractly in terms of the
Car.IsFast property. Lastly, let's create an implementation of the
SubaruWrx class can use any of the properties defined in
Car. It has
EngineType, etc. properties that are available, because it inherits from
Car inherits from
Automobile. You can cast
Car or to
Automobile, because it inherits from these base classes, and adds its own properties/methods. However, say you cast
Automobile; none of the properties/methods defined in
Car will be available, because all this object knows is that it's of type
Automobile. To gain access to those properties/methods, you must upcast to the appropriate type.
There are several ways that polymorphism can take place. The first is through class inheritance, which you see above. Class inheritance exposes the interface of the base class to all of the derived classes. Another option is
interface inheritance. The
interface declares a contract that the class must follow to implement the interface. In addition to class inheritance, an object can inherit from one or more interfaces, which adds properties/methods to the body of the class that it must provide implementation for. This is another common option that can be used in .NET development. Some languages offer the ability to inherit from multiple base classes; however, .NET is not one of those languages.
Examples of Polymorphism
There are many examples of Polymorphism in the .NET framework. One of them is the
Membership provider. When you call
Membership.GetUser or any other method, it calls the default provider, which is defined as a
MembershipProvider class. Any derivatives (
SqlMembershipProvider or other custom providers) expose the
MembershipProvider interface to create a concrete implementation. You can easily switch the underlying data store without having to change any code for the
When you work with a typed
dataset, the base objects for the tables/rows are inherited from
DataRow. These objects can be downcast to this base type. When downcast to this type, only the properties/methods defined in
DataTable/DataRow can be used, eliminating the strong-typing that comes from a typed
DetailsView web controls allow you to create custom fields, by creating a class that inherits from
DataControlField. Because of this, you do not have to create your own custom
GridView/DetailsView classes to expose new field types; you simply create a new field that inherits from
DataControlField, and create a custom implementation by overriding the base class's
Think of encapsulation as a black box; data is sent to a method, a lot of work goes on using the data, of which you don't know or care about. An output is returned to the caller. That is the process of encapsulation, or information hiding. Let's take a look at the following class:
From this class, we see a class that works with multi-line text, ensuring that the new line text is separated by line and retrieved by an index value. The
constructor takes a
string and parses the initial text. It also allows the adding and removing of lines. However, notice that the base object that stores the lines, the
CollectionBase object, is never exposed. Only certain object properties are exposed, but the list isn't directly exposed. This is information hiding, in that we don't need to expose the source object for subscriber to use it, but the subscriber can only use the exposed methods/properties to interact with it.
Why is encapsulation important? Using the above example, it would be really easy to change the underlying source to use a database, XML file, text file, or another data store, without breaking any code that the developer may have created. If the class exposed the list directly, any code that used the list would have to change, replacing it with database code. That makes using this class much harder to maintain and more likely that someone would stay away from using the class. But with the implementation above, nothing is known about the source and so switching the underlying data source is much easier.
This concept is prevalent throughout the .NET framework and any object-oriented development project, as it is important to hide certain information to the consumer of an object, because it aids in maintenance, development, and general use of the object.
This article walks through two of the biggest subjects in OO development, polymorphism and encapsulation, providing real concrete examples that developers can use to create better software.
The definition of polymorphism and information hiding (encapsulation) can be found on wikipedia.
Brian Mains is an application developer consultant with Computer Aid Inc. He formerly worked with the Department of Public Welfare.
In both places of business, he developed both windows and web applications, small and large, using the latest .NET technologies. In addition, he had spent many hou...
This author has published 73 articles on DotNetSlackers. View other articles or the complete profile here.
Please login to rate or to leave a comment.