Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

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). Of late, 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.

share|improve this question
    
The language you're using doesn't allow overloading constructors? –  Mat Jun 29 '12 at 5:47
1  
I am using Java.So Yes, it does allows and I think that could be one way to deal with this –  zswap Jun 29 '12 at 7:19
1  
I would note that if you have no public way to set class members after the fact, your class is effectively immutable. By allowing a public setter, you class now becomes mutable, and you may need to take this into consideration if you depended on immutability. –  cbojar Aug 7 at 3:26
    
I would say that if it needs to be set for your object to be valid, put it in every constructor... if it's optional (has a reasonable default) and you don't care about immutability, put it in a setter. It should be impossible to instantiate your object into an invalid state or after instantiation put it into an invalid state wherever possible. –  Bill K Oct 30 at 17:13

9 Answers 9

up vote 10 down vote accepted

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.
share|improve this answer

The advice to use constructors or builders is fine in general, but, in my experience, misses some key points for Actions, which

  1. Possibly need to be internationalized
  2. Are likely for marketing to change at the last minute.

I strongly suggest that the name, tooltip, icon etc... be read from a properties file, XML, etc. For example, for the File-Open action, you could pass in a Properties and it would look for

File.open.name=Open
File.open.tooltip=Open a file
File.open.icon=somedir/open.jpg

This is a format pretty easy to translate to French, to try a new better icon, etc. Without programmer time or a recompile.

This is just a rough outline, a lot is left to the reader... Look for other examples of internationization.

share|improve this answer

In the following proposed solution, superclass is abstract and has all three members set to a default value.

Subclass has different constructors so the programmer can instantiate it.

If first constructor is used, all members will have the default values.

If second constructor is used, you give an initial value to actionText member leaving other two members with the default value...

If third constructor is used, you instantiate it with a new value for actionText and toolTip, leaving imageURl whith the default value...

And so on.

public abstract class Action {
    protected String text = "Default action text";
    protected String toolTip = "Default action tool tip";
    protected String imageURl = "http://myserver.com/images/default.png";

    .... rest of code, I guess setters and getters
}

public class MyAction extends Action {


    public MyAction() {

    }

    public MyAction(String actionText) {
        setText(actionText);
    }

    public MyAction(String actionText, String toolTip_) {
        setText(actionText);
        setToolTip(toolTip_);   
    }

    public MyAction(String actionText, String toolTip_; String imageURL_) {
        setText(actionText);
        setToolTip(toolTip_);
        setImageURL(imageURL_);
    }


}
share|improve this answer

Just like kevin cline said in his answer, I think the way to go is to create a fluent API. I would just like to add that the fluent API works better when you have more than one property you may use.

It will make your code more readable, and from my point of view more easy and, aham, "sexy" to write.

In your case it would go like this (sorry for any typo, it has been a year since I wrote my last java program):

 public class MyAction extends Action {
    private String _text     = "";
    private String _tooltip  = "";
    private String _imageUrl = "";

    public MyAction()
    {
       // nothing to do here.
    }

    public MyAction text(string value)
    {
       this._text = value;
       return this;
    }

    public MyAction tooltip(string value)
    {
       this._tooltip = value;
       return this;
    }

    public MyAction image(string value)
    {
       this._imageUrl = value;
       return this;
    }
}

And the usage would be like this:

MyAction action = new MyAction()
    .text("My Action Text")
    .tooltip("My Action Tool tip")
    .image("Some Image");
share|improve this answer

Constructor overloading would be a simple and straightforward solution here:

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

It is better than calling .setText later, because this way nothing needs to be overwritten, actionText can be the intended thing right from the start.

As your code evolves and you will need even more flexibility (which will surely happen), you will benefit from the factory/builder pattern suggested by another answer.

share|improve this answer
    
What happens when they want to customize a second property? –  kevin cline Jun 29 '12 at 17:16
1  
For a 2nd, 3rd, .. property, you can apply the same technique, but the more properties you want to customize, the more unwieldy this becomes. At some point it will make more sense to implement a factory/builder pattern, as well said @michael-kjorling in his answer. –  janos Jun 29 '12 at 17:30

Add a fluent 'setText' method:

public class MyAction ... {
  ...
  public MyAction setText(String text) { ... ; return this; }
}

MyAction a = new MyAction().setText("xxx");

What could be clearer than that? If you decide to add another customizable property, no problem.

share|improve this answer
    
+1, I agree, and added another answer complementing with more properties. I think the fluent API is clearer to understand when you have more than 1 single property as an example. –  Machado Aug 17 '12 at 1:27

Think of how instances will be used and use a solution that will guide, or even force, the users to use those instances in the right, or at least best, manner. A programmer using this class will have a lot of other things to worry and think about. This class should not add to the list.

For instance, if the MyAction class is supposed to be immutable after construction (and possibly other initialization), it should not have a setter method. If most of the time it will use the default "My Action Text", there should be a parameterless constructor, plus a constructor that allows an optional text. Now the user doesn't need to think to use the class correctly 90% of the time. If the user usually ought to give some thought to the text, skip the parameterless constructor. Now the user is forced to think when necessary and can't overlook a necessary step.

If a MyAction instance needs to be mutable after full construction then you need a setter for the text. It's tempting to skip setting the value in the constructor (DRY principle--"Don't Repeat Yourself") and, if the default value is usually good enough I would. But if it's not, requiring the text in the constructor forces the user to think when they should.

Note that these users are not dumb. They just have too many real problems to worry about. By thinking about your class's "interface", you can keep it from becoming a real problem also--and an unnecessary one.

share|improve this answer

I think this is true if we are going to make a generic action class (like update, which is used to update Employee, Department ...). It’s all depends on scenario. If a specific action (like update employee) class (used many place in application - Update employee) is created with the intension to keep same text, tooltip and image at every place in the application (for consistency point of view). So hardcoding can be done for text, tooltip and image to provide the default text, tooltip and image. Still to give more flexibility, to customize these, it should have corresponding setter methods. Keeping in the mind only 10% places we have to change it. Taking action text every time from user can cause Different text every time for same action. Like 'Update Emp', 'Update Employee', 'Change Employee' or 'Edit Employee'. I am not sure but I think this can create the confusion to the user that this is something different.

share|improve this answer
    
I think overloaded constructor should still solve the problem. Because in all the "10%" cases, you will first create an Action with default text and then change the action text using "setText()" method. Why not set the appropriate text while constructing the action. –  zswap Jun 29 '12 at 10:21

It is useless to call setText(actionText) or setTooltip("My action tool tip") inside the constructor; it is easier (and you gain more performance) if you simply initialize the corresponding field directly:

    public MyAction(String actionText) {
        this.actionText = actionText;
    }

If you change actionText during the life time of the MyAction corresponding object, you should place a setter method; if not initialize the field only in constructor without providing a setter method.

Since tooltip and image are constants, treat them as constants; have fields:

private (or even public) final static String TOOLTIP = "My Action Tooltip";

Actually, when designing common objects (not beans or objects representing strictly data structures) it is a bad idea to provide setters and getters, since they kind of break encapsulation.

share|improve this answer
4  
Any half-way competent compiler and JITter should inline the setText() etc calls, so the performance difference between a function call to do an assignment, and having that assignment in place of the function call, should be negligible at most, and more likely than not zero. –  Michael Kjörling Jun 29 '12 at 7:52

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.