Part of the ObjectBasedProgramming
pattern language. Discussion occurs on PolymorphicFunctionDiscussion
Original at http://www.geocities.com/SiliconValley/Foothills/5962/polymorphicfunction.htm
Implement polymorphic operation without exposing the internal implementation.
True polymorphism enhances the potential of reuse, extensibility and maintainability. Polymorphism makes it possible to interact with an object without knowledge of its concrete class.
The implementation of the object-oriented concepts in a procedural language often requires additional implementation scaffolding. The underlying mechanisms providing the support should be completely hidden from the outside world. This implementation abstraction is necessary to provide the flexibility to modify the underlying mechanism in the future.
Apply the Polymorphic Function Pattern when
- More than one object would be instantiated from a class family
- Polymorphism is required
- The underlying mechanisms to support object-oriented concept such as abstraction and polymorphism must be hidden.
Each operation in the superclass and all subclasses map to a polymorphic function. This polymorphic function can operate on all subclasses in the class family that implemented the said operation. Its behaviour will differ to match the class of the object. This polymorphic function accepts an instance data structure as a parameter. The instance data structure is passed as an opaque type (In C it will be implemented as a *void).
The Polymorphic Function Pattern has four important consequences:
- Encapsulation. The interface and the implementation of the polymorphic function is de-coupled. The interface of a polymorphic function is also de-coupled from the internal structure of the instance data. As the polymorphic accepts the instance data as a opaque type (*void in C), it is possible to modify the underlying instance data structure without affecting the interface.
- True polymorphism. Any operation in a class family, no matter whether it is overridden in the subclassses, are implemented by a single function. Hence there is no need to determine the concrete class of an object before invoking its operation. As the function implementing an operation takes an opaque instance data as input, new subclasses can be added without ever changing the function interfaces.
- Invoking a non-existent operation. As the entire class family share a common set of polymorphic functions, it is possible to attempt to invoke an operation for an object which is not supported by the concrete class. A good implementation of the polymorphic function should signal an error under such circumstances.
- Potential conflict of operation name. If two subclasses independently extend the superclass by providing an operation of the same name, the definition of the operations must be identical. This is an consequence of mapping the two independent operations (with identical operation names) into one function.
- No type checking. As the instance data is accepted as an opaque type, the compiler would not be able to perform any type checking.
Consider the following class family:
The object diagram does not show the parameters and the return value type of the operations.
The operations getDescendentChangeCount():int and getChangeCount():int would be respectively implemented by functions with the following interfaces:
int ConditionFamilyGetDescendentChangeCount( void *pvInstance );
int ConditionFamilyGetChangeCount( void *pvInstance );
The operation reevaluateCondition(): is a private operation and therefore it does not have a public interface.
The subclasses Leaf alarm and Simple conditions independently extend the Condition class to provide the operation setState(bState: Boolean):. The operation would be implemented by a function with the following interface:
void ConditionFamilySetState( void *pvInstance, BOOL bState );
The Polymorphic Function pattern is fundamental to the application of object-based programming style described in this pattern language. This pattern has been extensively applied in the Network Management Unit Software (NUS) developed by MAS Technology. The Management Procedure Lock, the Condition Manager and the object handlers are implemented with the application of this pattern.
The interface of the polymorphic functions is described by this pattern. However this pattern does not address how to actually implement these functions. The FunctionPointer
pattern, and the PolymorphicFunctionWithEmbeddedBehaviour
pattern describe the techniques to implement an polymorphic function that can be performed on any instance in a class hierarchy.
Under some restricted conditions, operations need not be implemented as a function. An operation can be factored out and becomes a direct access to the instance data. This is described by the OperationVapourware
Polymorphic functions take instance data as inputs, which is described by the InstanceData