One more thing to take care of. OK, so we've got OOCalc calling Operations polymorphically now. We're still violating the OCP in Operation because if we need to add an operation, we need to create a subclass
and modify Operation. It would be nice if we could eliminate that duplicate work. Well, we can and here's how:
Notice that we don't really need multiple instances of concrete Operations. One instance of each will do. So, I'll turn all the concrete Operations into Singletons. I'll add a private constructor and a static getInstance() method to each concrete subclass. After doing this, I can eliminate the constants defined in Operation.
How does this affect my other code? Well, only the client code, as represented by OOCalcTest, will be affected. So instead of invoking the in(Operation) method with Operation.ADD we'll just invoke it with Addition.getInstance(), Subtraction.getInstance(), and Multiplication.getInstance(). A little more typing here maybe but look what happens: all we have to do now if we add a new operation is to create a new subclass of Operation! Here are the changes and the implementation of the Division operation:
<pre>
//Operation.java
package calc;
import java.util.Stack;
public abstract class Operation {
public static final Operation ADD = new Addition();
public static final Operation SUB = new Subtraction();
public static final Operation MUL = new Multiplication();
public abstract double perform(Stack operandStack);
}
//Addition.java
package calc;
import java.util.Stack;
public class Addition extends Operation {
private static Addition _instance;
public static Operation getInstance() {
if (_instance == null)
_instance = new Addition();
return _instance;
}
private Addition() {
super();
}
public double perform(Stack operandStack) {
double op1 = ((Double)(operandStack.pop())).doubleValue();
double op2 = ((Double)(operandStack.pop())).doubleValue();
return (op1 + op2);
}
}
//Subtraction.java
package calc;
import java.util.Stack;
public class Subtraction extends Operation {
private static Subtraction _instance;
public static Operation getInstance() {
if (_instance == null)
_instance = new Subtraction();
return _instance;
}
private Subtraction() {
super();
}
public double perform(Stack operandStack) {
double op1 = ((Double)(operandStack.pop())).doubleValue();
double op2 = ((Double)(operandStack.pop())).doubleValue();
return (op2 - op1);
}
}
//Multiplication.java
package calc;
import java.util.Stack;
public class Multiplication extends Operation {
private static Multiplication _instance;
public static Operation getInstance() {
if (_instance == null)
_instance = new Multiplication();
return _instance;
}
private Multiplication() {
super();
}
public double perform(Stack operandStack) {
double op1 = ((Double)(operandStack.pop())).doubleValue();
double op2 = ((Double)(operandStack.pop())).doubleValue();
return (op1 * op2);
}
}
//Division.java
package calc;
import java.util.Stack;
public class Division extends Operation {
private static Division _instance;
public static Operation getInstance() {
if (_instance == null)
_instance = new Division();
return _instance;
}
private Division() {
super();
}
public double perform(Stack operandStack) {
double op1 = ((Double)(operandStack.pop())).doubleValue();
double op2 = ((Double)(operandStack.pop())).doubleValue();
return (op2 / op1);
}
}
//OOCalc.java
package calc;
import java.util.Stack;
public class OOCalc {
private Stack operandStack = new Stack();
private Operation _op;
public double getResult() {
if (_op == null)
return 0.0;
return _op.perform(operandStack):
}
public void in(double operand) {
operandStack.push(new Double(operand));
}
public void in(Operation op) {
_op = op;
}
}
</pre>
Then make the
appropriate changes to OOCalcTest Compile and test. Green bar
[ March 29, 2002: Message edited by: Junilu Lacar ]