Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.getLastOperator() == 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);
    }
like image 617
Michiel Borkent Avatar asked Jan 21 '23 20:01

Michiel Borkent


2 Answers

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.

like image 188
Stephen C Avatar answered Mar 30 '23 01:03

Stephen C


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.
like image 20
BalusC Avatar answered Mar 30 '23 00:03

BalusC