|
Retrofitting the Legacy Code
One option available in implementing new classes MC (Master Card class) and Amex (American Express class) is extending the Visa class, but this is a bad choice, even if it provides 100% of the desired functionality. MC and Amex would then be functionally bound by Visa. Logically, these aren't proper class-subclass relationships, but in addition, any change specific to Visa would necessarily require MC and Amex to override the potentially changed behavior in Visa to keep their behavior consistent. So this is not a good option. The better option is to reuse functionality from Visa, while retrofitting a polymorphic relationship between the credit card classes and the handler code that uses them.
In order to accomplish this retrofitting, the following steps are taken:
1. Define a simple interface that encompasses all behavior common to all similar classes (in this case, Visa, MC, and Amex). All cards need an owner name, a number, an expiration date, and the ability to charge and credit, though charging and crediting behavior is unique to each card. Therefore, the new interface CreditCard declares four methods: setOwnerName, setCCNumber, setExpirationDate, charge, and credit.
2. Implement behavior common to all potential implementations of the CreditCard interface in an abstract class. Therefore, define an abstract class CreditCardAbs that implements CreditCard, and setOwnerName, setCCNumber, setExpirationDate methods, while passing on the requirement of implementing charge and credit methods to Visa, CM, and Amex. Since Visa has already implemented these methods, they can be moved from this class to CreditCardAbs.
3. Extend CreditCardAbs in Visa, MC, and Amex, providing unique implementations for the charge and credit methods in each subclass.
4. Change all method signatures and declarations in handler code that declare a Visa type to declare a CreditCard type instead.
| |
 |
Figure 2 | Completed design of retrofitted code.
|
The completed design is shown in Figure 2.
The application now uses polymorphism, and everywhere that Visa was once referenced, CreditCard is now referenced. The benefits of this new structure are plenteous. First, the handler code is valid for all implementations of CreditCard, and each implementation doesn't have to be handled separately. Second, supporting new types of credit cards no longer requires any changes to the handler code, as was required in the original design. Third, CreditCardAbs provides a single class in which all common behavior can be maintained, unlike the original Visa class, which provided a problematic inheritance situation.
As previously stated, all debugging, optimization, and enhanced functionality performed/implemented on this class will benefit all of its subclasses. Finally, in order to define a new credit card, only the CreditCardAbs abstract class must be implemented, from which all common functionality will be inherited.
It's Not Complicated
Polymorphism may sound complicated, but it isn't. Given some retrofitting here and there, a dusty, creaky, legacy application design can be reworked into a robust structure, built to last.
 | Brad O'Hearne is an independent developer, Java instructor, and Sun Certified Java Programmer, with extensive enterprise and Web development experience, located in Irvine, CA. Reach him at Brad can be contacted at brado@neurofire.com.
|
|