Design Patterns Explained Java Code Examples – Chapter 9: The Strategy Pattern

Chapter 9: The Strategy Pattern
Code Examples

Example

TOC

Example 9-1: Implementing the Strategy Pattern

TOC


Example

TOP

Switches, etc.
// Handle Tax
switch (myNation) {
    case US:
        // US Tax rules here
        break;
    case Canada:
        // Canadian Tax rules here
        break;
}
// Handle Currency
switch (myNation) {
    case US:
        // US Currency rules here
        break;
    case Canada:
        // Canadian Currency rules
        // here
        break;
}
// Handle Date Format
switch (myNation) {
    case US:
        // use mm/dd/yy format
        break;
    case Canada:
        // use dd/mm/yy format
        break;
}

But what happens when there are more variations? For example, suppose I need to add Germany to the list of countries and also add language as a result. Now, the code looks like this:

// Handle Tax
switch (myNation) {
    case US:
        // US Tax rules here
        break;
    case Canada:
        // Canadian Tax rules here
        break;
    case Germany:
        // Germany Tax rules here
        break;
}
// Handle Currency
switch (myNation) {
    case US:
        // US Currency rules here
        break;
    case Canada:
        // Canadian Currency rules
        // here
        break;
    case Germany:
        // Euro Currency rules here
        break;
}
// Handle Date Format
switch (myNation) {
    case US:
        // use mm/dd/yy format
        break;
    case Canada:
    case Germany:
        // use dd/mm/yy format
        break;
}
// Handle Language
switch (myNation) {
    case US:
    case Canada:
        // use English
        break;
    case Germany:
        // use German
        break;
}

This still is not too bad, but notice how the switches are not quite as nice as they used to be. There are now fall-throughs. But then I need to start adding variations within a case. Suddenly, things get bad in a hurry. For example, to add French in Quebec, my code looks like this:

// Handle Language
switch (myNation) {
    case Canada:
    if (inQuebec) {
        // use French
        break;
    }
    case US:
        // use English
        break;
    case Germany:
        // use German
        break;
}

Step 2: Favor aggregation


Example 9-1: Implementing the Strategy Pattern

TOP

public class TaskController {
    public void process () {
        // this code is an emulation of a 
        // processing task controller
        // . . .
        // figure out which country you are in
        CalcTax myTax;
        myTax= getTaxRulesForCountry();
        SalesOrder mySO= new SalesOrder();
        mySO.process(myTax);
    }
    private CalcTax getTaxRulesForCountry() {
        // In real life, get the tax rules based on
        // country you are in. You may have the
        // logic here or you may have it in a
        // configuration file
        // Here, just return a USTax so this 
        // will compile.
        return new USTax();
    }
}
public class SalesOrder {
    public void process (CalcTax taxToUse) {
        long itemNumber= 0;
        double price= 0;
        // given the tax object to use
        // . . .
        // calculate tax
        double tax = taxToUse.taxAmount(itemNumber,price);
    }
}
public abstract class CalcTax {
    abstract public double taxAmount(long itemSold,double price);
}
public class CanTax extends CalcTax {
    public double taxAmount(long itemSold,double price) {
        // in real life, figure out tax according to
        // the rules in Canada and return it
        // here, return 0 so this will compile
        return 0.0;
    }
}
public class USTax extends CalcTax {
    public double taxAmount(long itemSold,double price) {
        // in real life, figure out tax according to
        // the rules in the US and return it
        // here, return 0 so this will compile
        return 0.0;
    }
}