Handling New Requirements

After writing this application, suppose I receive a new requirement to change the way I have to handle taxes. Now, I have to be able to handle taxes on orders from customers outside the United States. At a minimum, I will need to add new rules for computing these taxes.

How can I handle these new rules? I could attempt to reuse the existing SalesOrder object, processing this new situation like a new kind of sales order, only with a different set of taxation rules. For example, for Canadian sales, I could derive a new class called CanadianSalesOrder from SalesOrder that would override the tax rules. I show this solution in Figure 14-2.

Figure 14-2. Sales order architecture for an e-commerce system.


Now, design patterns repeatedly demonstrate a fundamental rule of design patterns: “Favor object composition over class inheritance.”[4] The solution in Figure 14-2 does just the opposite! In other words, I have handled the variation in tax rules by using inheritance to derive a new class with the new rule.

[4] ibid, p. 20.

How could I approach this differently? Following the rules I stated earlier: attempt to “consider what should be variable in your design” … and “encapsulate the concept that varies.”[5]

[5] ibid, p. 29.

Following this two-step approach, I should do the following:

1.
Find what varies and encapsulate it in a class of its own.

2.
Contain this class in another class.

In this example, I have already identified that the tax rules are varying. To encapsulate them would mean creating an abstract class that defines how to accomplish taxation conceptually, and then derive concrete classes for each of the variations. In other words, I could create a CalcTax object that defines the interface to accomplish this task. I could then derive the specific versions needed. I show this in Figure 14-3.

Figure 14-3. Encapsulating tax rules.


Continuing on, I now use composition instead of inheritance. This means, instead of making different versions of sales orders (using inheritance), I will contain the variation with composition. That is, I will have one SalesOrder class and have it contain the CalcTax class to handle the variations. I show this in Figure 14-4.

Figure 14-4. Favoring composition over inheritance.


UML Diagrams

In the UML, it is possible to define parameters in the methods. This is done by showing a parameter and its type in the parenthesis of the method.

Thus, in Figure 14-4, the taxAmount method has three parameters:

  • itemSold of type Salable

  • qty of type double

  • price of type double

All of these are inputs denoted by the “in.” The taxAmount method also returns a double.


I have defined a fairly generic interface for the CalcTax object. Presumably, I would have a Saleable class that defines saleable items (and how they are taxed). The SalesOrder object would give that to the CalcTax object, along with the quantity and price. This would be all the information the CalcTax object would need.

Another advantage of this approach is that cohesion has improved. Sales tax is handled in its own class. Another advantage is that as I get new tax requirements, I simply need to derive a new class from CalcTax that implements them.

Finally, it becomes easier to shift responsibilities. For example, in the inheritance-based approach, I had to have the TaskController decide which type of SalesOrder to use. With the new structure, I can have either the TaskController do it or the SalesOrder do it. To have the SalesOrder do it, I would have some configuration object that would let it know which tax object to use (probably the same one the TaskController was using). I show this in Figure 14-5.

Figure 14-5. The SalesOrder object using Configuration to tell it which CalcTax to use.


This approach allows the business rule to vary independently from the SalesOrder object that uses it. Note how this works well for current variations I have as well as any future ones that might come along. Essentially, this use of encapsulating an algorithm in an abstract class (CalcTax) and using one of them at a time interchangeably is the Strategy pattern.

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

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