WeVie
WeVie

Reputation: 598

Which is the better constructor? Empty or using fields?

I am currently taking an Android class and when I got the first assignment grade, I lost points due to using an empty constructor rather than using one with fields. The professor said using fields is better. Is he correct? If so, why?

Is this better?

Photos pic = new Photos(path, title, author, date);

public Photos(String url_path, String title, String author,
        String date_taken) {
    super();

    this.url_path = url_path;
    this.title = title;
    this.author = author;
    this.date_taken = date_taken;
} 

Or this? Or does it matter?

 Photos pic = new Photos();
 pic.setUrl_path(path);
 pic.setTitle(title);
 pic.setAuthor(author);
 pic.setDate_taken(date);

 public Photos() {
    super();

 }

Upvotes: 4

Views: 195

Answers (8)

Raedwald
Raedwald

Reputation: 48634

In general, you should prefer a constructor that is given initial values, to setting those values later using setter methods. But why?

It is possible to just think of an object as a bag for holding a jumbled collection of fields, which in theory could have any value, including invalid values. In that case, using a no-args constructor followed by a setter would be OK.

But it transpired (in the 1970s) that programming in that way caused difficulties when creating large or complicated programs.

Imagine you had a Person class that had an attribute that recorded the name of the person, as a String, and the nature of your program was that you will, and must, always know the name of a person. As you must always have the name, it must never be null. If you have a no-args constructor, what value would it initialise the name to? It is not permitted to leave the name as null. But it makes no sense to set the name to an arbitrary default name, because there is no generally useful default for the name of a person. So, if you want to impose the constraint that a Person object always has a (non null) name, your constructor must have an argument that tells it what the name of the new Person object will be.

It is useful to think of an object, not as a jumble of values, but as values that have constraints on them. It is very helpful if the code for that object is written in a way that makes it impossible to breach those constraints. Then, any code that uses that object can safely assume those constraints will be met, even if you do not know (or remember) what the other parts of the code do. This enables you to concentrate on one bit of the code at once, without having to examine elsewhere to check whether an important constraint will be met. In most cases, only constructors given initial values can construct an object that meets all the constraints.

Upvotes: 1

BatScream
BatScream

Reputation: 19700

As pointed out by Dmitry Bychenko in the comments, parameters are passed via the constructor, When the construction of an object depends upon those mandatory parameters.

The other parameters are generally set once the object has been constructed.

Take the example of the constructor of the File class,

File f = new File("filepath");

Here filepath is a parameter without which a File object cannot be constructed, since it needs to refer to a location where the file resides. And its attributes such as readable, can be set through the setters, and come into picture only after the file reference has been constructed successfully.

f.setReadable(arg0)

Since in your example, the Photo class doesn't depend upon any of its parameter values for its construction, a parameterized constructor is not necessary.

Upvotes: 2

HCP
HCP

Reputation: 1042

If your object Photo (in this case) always has those attributes to be a valid photo I believe you should include the assignment of those attributes in your constructor. (path, title, author, date);

And since your are making one photo object. The name of the constructor and class should be Photo (not Photos)

public Photo(String urlPath, String title, String author,
    String dateTaken) {
super();

this.urlPath= urlPath;
this.title = title;
this.author = author;
this.dateTaken= dateTaken;

}

Some more comments:

You only need to call super() if the Photo class is a derived class. Use camel casing for your argument names and try to be consistent.

Upvotes: 1

Anand Rajasekar
Anand Rajasekar

Reputation: 837

Another aspect of consideration is how you want to wire together classes. If you are using dependency injection container like spring or guice, a empty constructor with setters and getters allows you to wire references from and to your object.

I prefer to separate object construction from execution, so as long as your code is factored in that way it would be modular, extensible and clean.

Upvotes: 1

StackFlowed
StackFlowed

Reputation: 6816

When you use setter the objects are mutable and their state can be manipulated but anyone who has access to it.

The other approach makes the objects in a single defined state and are typically read-only once they are created as they cannot be modified from outside the class. How ever they can always be mutated inside the class.

Example:

public class Setters {
   private int value;
   public void setValue(int val) {
     value=val;
   }
   public int getValue() {
     return value;
   }
}

public void function(Setter setter){
    setter.setValue(20);
}


// In main 

Setter setter = new Setter();
setter.setValue(10);
function(setter);
System.out.println(setter.getValue());

In this case it will print 20 cause it is mutable

public class Setters {
   private int value;
   public setter(int val) {
     value=val;
   }
   public int getValue() {
     return value;
   }
}

// In main 

Setter setter = new Setter(10);
Setter setter1 = new Setter(20);
System.out.println(setter.getValue());
System.out.println(setter1.getValue());

This will print 10 and 20 you don't have a setter so these object will become read only after creation.

Upvotes: 2

Murtaza Zaidi
Murtaza Zaidi

Reputation: 597

Depends what class you are writing. If it is for Immutable objects it means you are not to provide accessors / mutators for it. In that case its necessary that you provide initial values for attributes at time of creation of object. Natural choice would be to pass them in constructor.

In your case of Photos, the attributes like Title, Date_Taken and Author are not supposed to be changed or can't be null and are supposed to be associated with "Photos" right from the creation, so it is better practice to provide arguments in constructor. Although you can provide getter/setter for URL since its value can change with time.

Upvotes: 1

David
David

Reputation: 218808

Neither is "better", they simply do different things. Which one is subjectively "better" depends on what you want to achieve with that class. Consider this code for example:

Photos pic = new Photos();
pic.setUrl_path(path);
pic.setTitle(title);
pic.setAuthor(author);
pic.setDate_taken(date);

Immediately following that first line, is the pic object in a valid state? Does having no values set result in a meaningfully and contextually complete Photos object? If the answer is "no" and if the fields being set are necessary in order to have a valid Photos object, then they should be required by the constructor.

That is, the job of the constructor is to ensure that only a valid instance is created. Never assume that consuming code will follow up with setters, it might not. The job of ensuring valid state of the object is a responsibility that should be encapsulated within the object.

On the other hand, if a parameterless constructor can create a valid instance of Photos then it's perfectly acceptable to have a parameterless constructor. You can have both, so consuming code has the option of which to use depending on the state is wishes to create:

public Photos() {
    // set default values
}

public Photos(String url_path, String title, String author, String date_taken) {
    // set supplied values
}

It all depends on what a valid state of a Photos object can be and what is required (or not required) in order to achieve that state.

Upvotes: 4

DreadHeadedDeveloper
DreadHeadedDeveloper

Reputation: 620

In terms of efficiency, yeah, it is.

You could do it like this...

JButton b = new JButton();
b.setText("Hello everybody 1");
b.setIcon(b1);

JButton c = new JButton();
c.setText("Hello everybody 2");
c.setIcon(c2);

JButton d = new JButton();
d.setText("Hello everybody 3");
d.setIcon(d3);

JButton e = new JButton();
e.setText("Hello everybody 4");
e.setIcon(e4);

Or you could do

JButton b = new JButton("Hello everybody 1", b1);

JButton c = new JButton("Hello everybody 2", c2);

JButton d = new JButton("Hello everybody 3", d3);

JButton e = new JButton("Hello everybody 4", e4);

Far more streamlined, yes? Not to mention that things like variables, of which most classes have several, can be given default values from the getgo, instead of having to give them passive values when you are not even going to use those variables anywhere in your program.

Upvotes: 1

Related Questions