Java – Use Constructor or Setter Method?

designjavaobject-orientedrefactoring

I am working on a UI code where I have an Action class, something like this –

public class MyAction extends Action {
    public MyAction() {
        setText("My Action Text");
        setToolTip("My Action Tool tip");
        setImage("Some Image");
    }
}

When this Action class was created, it was pretty much assumed that the Action class won't be customizable (in a sense – its text, tooltip or image will be not be changed anywhere in the code). Now, we are in need of changing the action text at some location in code. So, I suggested my co-worker to remove the hardcoded action text from the constructor and accept it as an argument, so that everybody is forced to pass the action text. Something like this code below –

public class MyAction extends Action {
    public MyAction(String actionText) {
        setText(actionText);
        setTooltip("My Action tool tip"); 
        setImage("My Image"); 
    }
}

He, however, thinks that since setText() method belongs to base class it can be flexibly used to pass the action text wherever action instance is created. That way, there is no need to change the existing MyAction class. So his code would look something like this.

MyAction action = new MyAction(); //this creates action instance with the hardcoded text
action.setText("User required new action text"); //overwrite the existing text.

I am not sure if that is a correct way to deal with problem. I think in above mentioned case user is anyway going to change the text, so why not force him while constructing the action? The only benefit I see with the original code is that user can create Action class without much thinking about setting text.

Best Answer

The only benefit I see with the original code is that user can create Action class without much thinking about setting text.

That is actually not a benefit, for most purposes it's a drawback and in the remaining cases I'd call it a tie. What if someone forgets to call setText() after construction? What if that is the case in some unusual case, perhaps an error handler? If you want to really force the text to be set, you need to force it at compilation time, since only compile-time errors are actually fatal. Anything that happens at run-time depends on that particular code path being executed.

I see two clear paths forward:

  1. Use a constructor parameter, as you suggest. If you really want to, you can pass null or an empty string, but then the fact that you are not assigning a text is explicit rather than implicit. It's easy to see the existence of a null parameter and see that there was probably some thought put into it, but not so easy to see the lack of a method call and determine if the lack of such was intentional or not. For a simple case like this, this is probably the approach I would take.
  2. Use a factory/builder pattern. This may be overkill for such a simple scenario, but in a more general case it is highly flexible as it allows you to set any number of parameters, and check preconditions before or during object instantiation (if constructing the object is a large operation and/or the class can be used in more than one way, this can be a huge advantage). Particularly in Java it is also a common idiom, and following established patterns in the language and framework you are using is very rarely a bad thing.