Applying the Singleton Pattern to the Case Study
A motivating example: Instantiate tax calculation strategies only once and only when needed |
In Chapter 9, I encapsulated the rules about taxes within strategy objects. I have to derive a CalcTax class for each possible tax calculation rule. This means that I need to use the same objects over and over again, just alternating between their uses.
For performance reasons, I might not want to keep instantiating them and throwing them away again and again. And, although I could instantiate all of the possible strategies at the start, this could become inefficient if the number of strategies grew large. (Remember, I may have many other strategies throughout my application.) Instead, it would be best to instantiate them as needed, but only do the instantiation once.
The problem is that I do not want to create a separate object to keep track of what I have already instantiated. Instead, I would like the objects themselves (that is, the strategies) to be responsible for handling their own single instantiation.
Singleton makes objects responsible for themselves
This is the purpose of the Singleton pattern. It enables me to instantiate an object only once, without requiring the client objects to be concerned with whether it already exists.
The Singleton could be implemented in code as shown in Example 21-1. In this example, I create a method (getInstance) that will instantiate at most one USTax object. The Singleton protects against someone else instantiating the USTax object directly by making the constructor private, which means that no other object can access it.
Example 21-1. Java Code Fragment: Singleton Pattern
public class USTax extends Tax { private static USTax instance; private USTax() { } public static USTax getInstance() { if (instance== null) instance= new USTax(); return instance; } }
Singleton with polymorphism |
In this case study, however, I actually need the SalesOrder to ask the Tax object which Tax object to use. The reason for this is that the SalesOrder does not want to know which particular tax object is present. There are two notions being combined here:
-
Hide which concrete class I use (the factory in a method in the Tax class)
-
Hide how many instantiations of each class I have (the Singleton in the USTax and other Tax concrete classes).
I show this in Example 21-2.
Example 21-2. Java Code Fragment: Singleton Pattern in the Context of the E-Commerce System
abstract public class Tax { static private Tax instance; protected Tax() { }; abstract double calcTax( double qty, double price); public static Tax getInstance() { // use whatever rule you use to determine // which tax object to use. For now, // let's create a USTax object. instance= USTax.getInstance(); return instance; } } public class USTax extends Tax { private static USTax instance; private USTax() { } // Note in the following, I had to change USTax // to Tax since I used the same "getInstance" // name. public static Tax getInstance() { if (instance== null) instance= new USTax(); return instance; } }