Refactoring some code with 'instanceof' to overloaded method solution in Java
I have this piece of code from GWT in Action:
public void processOperator(final AbstractOperator op) {
System.out.println("Wordt deze ooit aangeroepen?");
if (op instanceof BinaryOperator) {
if ((data.getLast开发者_如何转开发Operator() == null) || (data.isLastOpEquals())) {
data.setBuffer(Double.parseDouble(data.getDisplay()));
data.setInitDisplay(true);
} else {
data.getLastOperator().operate(data);
}
data.setLastOperator(op);
} else if (op instanceof UnaryOperator) {
op.operate(data);
}
data.setLastOpEquals(false);
}
I want to eliminate the 'instanceof' part by using method dispatching:
public void processOperator(final BinaryOperator op) {
if ((data.getLastOperator() == null) || (data.isLastOpEquals())) {
data.setBuffer(Double.parseDouble(data.getDisplay()));
data.setInitDisplay(true);
} else {
data.getLastOperator().operate(data);
}
data.setLastOperator(op);
data.setLastOpEquals(false);
}
public void processOperator(final UnaryOperator op) {
op.operate(data);
data.setLastOpEquals(false);
}
But now I run into trouble in the code below from class ButtonOperator. The following code has AbstractOperator as a type in the constructor. The code for the types UnaryOperator and BinaryOperator would look exactly the same, so it feels a little cumbersome having to make special constructors for them containing the exact same code. What is a better approach?
public ButtonOperator(final CalculatorController controller,
final AbstractOperator op) {
super(op.label);
this.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
controller.processOperator(op);
}
});
this.setStyleName(CalculatorConstants.STYLE_BUTTON);
}
Unfortunately, this won't work. When you have overloaded methods, the decision about which one is called is made at compile time based on the static type of the argument expressions. For example:
UnaryOperator uop = new UnaryOperator(...);
AbstractOperator aop = uop;
...
// This will call the "unary" version of the method
processOperator(uop);
// This will call the "abstract" version of the method
processOperator(aop);
You only get runtime dispatching of method calls when methods are overridden.
Stephen C explained the cause.
To solve this, you can decide to either move the processOperator()
method to the AbstractOperator
class and have the concrete classes implement it:
op.processOperator(controller);
Or make use of the visitor pattern:
op.processOperator(this); // this = controller.
精彩评论