22.1. Polymorphism

When related alternatives or behaviors vary by type (class), assign responsibility for the behavior—using polymorphic operations—to the types for which the behavior varies.[1]

[1] Polymorphism has several related meanings. In this context, it means “giving the same name to services in different objects” [Coad95] when the services are similar or related. The different object types usually implement a common interface or are related in an implementation hierarchy with a common superclass, but this is language-dependent; for example, dynamic binding languages such as Smalltalk do not require this.

Solution


Corollary: Do not test for the type of an object and use conditional logic to perform varying alternatives based on type.

How to handle alternatives based on type? How to create pluggable software components?

Problem


Alternatives based on type— Conditional variation is a fundamental theme in programs. If a program is designed using if-then-else or case statement conditional logic, then if a new variation arises, it requires modification of the case logic. This approach makes it difficult to easily extend a program with new variations because changes tend to be required in several places—wherever the conditional logic exists.

Pluggable software components— Viewing components in client-server relationships, how can you replace one server component with another, without affecting the client?

In the NextGen POS application, there are multiple external third-party tax calculators that must be supported (such as Tax-Master and Good-As-Gold TaxPro); the system needs to be able to integrate with different ones. Each tax calculator has a different interface, and so there is similar but varying behavior to adapt to each of these external fixed interfaces or APIs. One product may support a raw TCP socket protocol, another may offer a SOAP interface, and a third may offer a Java RMI interface.

Example


What objects should be responsible for handling these varying external tax calculator interfaces?

Since the behavior of calculator adaptation varies by the type of calculator, by Polymorphism we should assign the responsibility for adaptation to different calculator (or calculator adapter) objects themselves, implemented with a polymorphic getTaxes operation (see Figure 22.1).

Figure 22.1. Polymorphism in adapting to different external tax calculators.


These calculator adapter objects are not the external calculators, but rather, local software objects that represent the external calculators, or the adapter for the calculator. By sending a message to the local object, a call will ultimately be made on the external calculator in its native API.

Each getTaxes method takes the Sale object as a parameter, so that the calculator can analyze the sale. The implementation of each getTaxes method will be different: TaxMasterAdapter will adapt the request to the API of Tax-Master, and so on.

UML notation— Figure 22.1 introduces some new UML notation for specifying interfaces (a descriptor of operations without implementation), interface implementation, and for “collection” return types; Figure 22.2 elaborates. A UML stereotype is used to indicate an interface; a stereotype is a mechanism to categorize an element in some way. A stereotype name is surrounded by guillemets symbols, as in «interface». Guillemets are special single-character brackets most widely known by their use in French typography to indicate a quote; but to quote Rumbaugh, “the typographically challenged could substitute two angle brackets (<< >>) if necessary” [RJB99].

Figure 22.2. UML notation for interfaces and return types.


Polymorphism is a fundamental principle in designing how a system is organized to handle similar variations. A design based on assigning responsibilities by Polymorphism can be easily extended to handle new variations. For example, adding a new calculator adapter class with its own polymorphic getTaxes method will have minor impact on the existing design.

Discussion


Sometimes, developers design systems with interfaces and polymorphism for speculative “future-proofing” against an unknown possible variation. If the variation point is definitely motivated by an immediate or very probable variability, then the effort of adding the flexibility through polymorphism is of course rational. But critical evaluation is required, because it is not uncommon to see unnecessary effort being applied to future-proofing a design with polymorphism at variation points that in fact are improbable and will never actually arise. Be realistic about the true likelihood of variability before investing in increased flexibility.

Contraindications


  • Extensions required for new variations are easy to add.

    Benefits


  • New implementations can be introduced without affecting clients.

  • Protected Variations

    Related Patterns


  • A number of popular GoF design patterns [GHJV95], which will be discussed in this book rely on polymorphism, including Adapter, Command, Composite, Proxy, State, and Strategy.

Choosing Message, Don't Ask “What Kind?”

Also Known As; Similar To


..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.149.235.63