6.4. Polymorphism

 <  Day Day Up  >  

Polymorphism deals with manipulating objects of different classes using only the interface that they have in common. There are two different uses for polymorphism . In the first case, there are different implementations of an interface with the same behavior, such as with printer drivers. In the second case, there are different behaviors with the same interface, such as proxy classes with different operations.

You can code classes to be polymorphic in two ways. [*] One way is to use inheritance. Derived classes share the interface of the base class. The second way is to implement interfaces in languages such as Java and C#.

[*] A reviewer noted that in Ruby, there is a third way called Duck Typing, whereby any class with a matching method name can handle a method. It does not have to implement an interface or extend a base class.

6.4.1. Using Inheritance

A typical example of an inheritance hierarchy has a Shape base class. Shapes such as Rectangle and triangle are derived from Shape , as shown in Figure 6-1. A Square shape is then derived from Rectangle , and an EquilateralTriangle is derived from triangle .

An EquilateralTriangle and a Square have a facet in common that is not represented in this inheritance hierarchy. They both represent regular polygons (all their sides are the same length).

6.4.2. Using Interfaces

Instead of using inheritance, you could code the relationship with interfaces, as shown in Figure 6-2.

When Square s and EquilateralTriangle s are added, they can implement a RegularPolygon interface as well as the Shape interface, as shown in Figure 6-3.

The disadvantage of using interfaces is that each class that implements an interface must code each method in the interface. For example, EquilateralTriangle and Square both need to have code for the set_length_of_side( ) method. If the code is the same, the common

Figure 6-1. Shapes using inheritance

Figure 6-2. Shapes using an interface

code could be placed in a set_length_of_side( ) method in a RegularPolygonImplementation class. The set_length_of_side( ) methods in EquilateralTriangle and Square would call that method.

An advantage of using interfaces is that the relationship between the classes is fluid. After having experience in using the classes, you might find that RegularPolygon s actually have a lot more in common than a Square and a Rectangle . Instead of prematurely creating an inheritance hierarchy that ties Square into Rectangle , thinking in interfaces allows these relationships to develop.

Figure 6-3. Shapes using an additional interface

THINK INTERFACES, NOT INHERITANCE

Interfaces provide more fluidity in the relationships between classes .


Frameworks that use inheritance can often be designed with interfaces. For example, a Component class is often the base class of a GUI hierarchy, as shown in Example 6-1. With inheritance, it can be unclear which methods of the base class should be overridden by derived classes.

Example 6-1. Component with inheritance
 class Component     {     draw( );     hide( );     } class MyComponent extends Component     {     // What should it override?     } 

Alternatively, the class could require that an interface be implemented, as shown in Example 6-2 and Figure 6-4. Custom components would implement the interface, which makes clear what methods need to be created.

Example 6-2. Component with delegation to interface
 interface Component     {     draw( );     } class BaseComponent     {     Component  a_component;     draw( )         {         a_component.draw( );         }     } class MyComponent implements Component     {     draw( )         {         // Particular draw         }     } 

Figure 6-4. A framework using strategy

 <  Day Day Up  >  


Prefactoring
Prefactoring: Extreme Abstraction, Extreme Separation, Extreme Readability
ISBN: 0596008740
EAN: 2147483647
Year: 2005
Pages: 175
Authors: Ken Pugh

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net