OO Design: What goes into the constructor?

A

antonyliu2002

I have always been wondering about this question: How do we decide
what should be put into the constructor?

For example, a Project class can have a lot of attributes, such as
ProjectID, ProjectName, ProjectManagerID, ProjectDescription,
ProjectObjective, ProjectProgramAreaID, ProjectStatus, ProjectFundID,
ProjectFundStatus, ProjectSchedule, etc.

Now, when I am writing the Project class, how do I decide which and
which of such information go to the constructor(s)? It apparently
does not make sense to cram all of them into a single constructor,
right? And if we decide to have multiple constructors, what
information needs to be selected and put into which constructor?

I am confused, please shed some light on this issue. Thank you.
 
T

tzvika.barenholz

I have always been wondering about this question: How do we decide
what should be put into the constructor?

For example, a Project class can have a lot of attributes, such as
ProjectID, ProjectName, ProjectManagerID, ProjectDescription,
ProjectObjective, ProjectProgramAreaID, ProjectStatus, ProjectFundID,
ProjectFundStatus, ProjectSchedule, etc.

Now, when I am writing the Project class, how do I decide which and
which of such information go to the constructor(s)? It apparently
does not make sense to cram all of them into a single constructor,
right? And if we decide to have multiple constructors, what
information needs to be selected and put into which constructor?

I am confused, please shed some light on this issue. Thank you.

1. It's generally a good idea to make objects immutable, and put
*everything* in the constructor.

2. If you do find yourself creating multiple constructors, i.e.
because some properties are optional - use static factory methods that
drain into one private constructor. That way you can give them names
that make sense.

3. If you find yourself with an unmanageably large number of
parameters in the constructor, it's usually a good sign that you've
got an unmanageably large number of properties in the class. take the
opportunity to refactor it, break it up, group certain properties into
classes of their own, if it makes sense, and so on.

T
 
J

Joe Attardi

1. It's generally a good idea to make objects immutable, and put
*everything* in the constructor.
In some cases, sure, but I don't know if I'd call this a general rule.
Why do you say objects should generally be immutable?
 
T

Thomas Hawtin

3. If you find yourself with an unmanageably large number of
parameters in the constructor, it's usually a good sign that you've
got an unmanageably large number of properties in the class. take the
opportunity to refactor it, break it up, group certain properties into
classes of their own, if it makes sense, and so on.

Before that you might consider using a builder. That way you can build
up the object one (labeled) property at a time.

So the original example would become:

Project project = new Project.Builder()
.id(id)
.name(name)
.description(description)
.objective(objective)
.programAreaID(programAreaID)
.status(status)
.fundID(fundID)
.fundStatus(fundStatus)
.schedule(schedule)
.create();

Tom Hawtin
 
A

antonyliu2002

1. It's generally a good idea to make objects immutable, and put
*everything* in the constructor.

2. If you do find yourself creating multiple constructors, i.e.
because some properties are optional - use static factory methods that
drain into one private constructor. That way you can give them names
that make sense.

3. If you find yourself with an unmanageably large number of
parameters in the constructor, it's usually a good sign that you've
got an unmanageably large number of properties in the class. take the
opportunity to refactor it, break it up, group certain properties into
classes of their own, if it makes sense, and so on.

T

Yes, I do quite often find myself flooded with a large number of
parameters which I attempt to place in the constructor(s). You say
that in such cases, we may be able to break it into smaller classes.
But does it make sense to break the Project class into multiple
smaller classes?

Or is it better to simply put the ProjectID and ProjectName in the
constructor, and make all other attributes/properties/fields (such as
ProjectDescription, ProjectObjective, ProjectManagerID,
ProjectStartDate, ProjectContractorID, ProjectFundSourceID,
ProjectActualCost) available in the getter and setter methods?
 
A

antonyliu2002

Before that you might consider using a builder. That way you can build
up the object one (labeled) property at a time.

So the original example would become:

Project project = new Project.Builder()
.id(id)
.name(name)
.description(description)
.objective(objective)
.programAreaID(programAreaID)
.status(status)
.fundID(fundID)
.fundStatus(fundStatus)
.schedule(schedule)
.create();

Tom Hawtin

Tom, are those dotted identifiers (.id, .name, .description, etc.)
setter methods? I am confused by the syntax.
 
T

tzvika.barenholz

In some cases, sure, but I don't know if I'd call this a general rule.
Why do you say objects should generally be immutable?

I merely repeat after Bloch, so I can't take the credit. Immutability
makes code easier to debug, because objects don't go changing on you.
It also makes objects fit well within frameworks like collections
(imagine putting something in a hash set, then changing its internal
state which gives it a different hashcode).

Of course not everything can be immutable, because some object do
genuinely change state without stopping to be themselves. In other
cases the cost of construction and instantiation prohibits it. But I
think generally immutable is the way to go :)

T
 
K

kaldrenon

I merely repeat after Bloch, so I can't take the credit. Immutability
makes code easier to debug, because objects don't go changing on you.

I know there are cases where this is true. But the way I see it,
there's immutable, and there's /immutable/.

There are plenty of instances where one is using a class to represent
a collection of information and knows full well that the information
is going to receive updates over time. How one goes about making those
updates is a matter of style, and good OO with encapsulation suggests
that it's better to give the class a behavior than to perform the
behavior outside of the class and modify within (e.g. a deposit()
method instead of a setBalance() method for a Bank). But if every one
of your classes is solely a grouping of data and no behaviors....well
at the very least, that's boring. but it doesn't sound all that
helpful, either.

So when you say immutability, are you referring to something like not
using setters, or something more absolute?
 
C

Chris Riesbeck

Tom, are those dotted identifiers (.id, .name, .description, etc.)
setter methods? I am confused by the syntax.

I think Tom is referring to the Builder pattern

http://en.wikipedia.org/wiki/Builder_pattern

In Project you define an inner class Builder.

..id(), .name() etc are methods of Project.Builder that add labelled data
to a Project.Builder instance. They all return "this" so methods can be
chained.

..create() is a method that takes that instance data and returns a newly
constructed Project.

So the opening line, "new Project.Builder()" creates an empty
Project.Builder instance, and the rest of the lines fill it in, and the
final line returns the Project.
 
W

Wojtek

Chris Riesbeck wrote :
I think Tom is referring to the Builder pattern

http://en.wikipedia.org/wiki/Builder_pattern

In Project you define an inner class Builder.

.id(), .name() etc are methods of Project.Builder that add labelled data to a
Project.Builder instance. They all return "this" so methods can be chained.

.create() is a method that takes that instance data and returns a newly
constructed Project.

So the opening line, "new Project.Builder()" creates an empty Project.Builder
instance, and the rest of the lines fill it in, and the final line returns
the Project.

Just make sure that the create() method does a sanity check to ensure
that ALL the required information has been set. So someone does not
simply call:

Project project = new Project.Builder().create();
 
R

Rob

I have always been wondering about this question: How do we decide
what should be put into the constructor?

For example, a Project class can have a lot of attributes, such as
ProjectID, ProjectName, ProjectManagerID, ProjectDescription,
ProjectObjective, ProjectProgramAreaID, ProjectStatus, ProjectFundID,
ProjectFundStatus, ProjectSchedule, etc.

Now, when I am writing the Project class, how do I decide which and
which of such information go to the constructor(s)? It apparently
does not make sense to cram all of them into a single constructor,
right? And if we decide to have multiple constructors, what
information needs to be selected and put into which constructor?

I am confused, please shed some light on this issue. Thank you.
This is a good question.

What I've found works well is the constructor contains the minimal
amount to create a valid instance of the object with setters for the
other stuff.

If you know how the client code will be used this can be helpful. For
a small number of fields where the client has all the information at
hand when he creates the object then the constructor can specify
everything.

In the project example it is quite possible that at the time the
client needs to create a Project he may only have some of the data at
hand and will need to get the rest later. So I'd let the client create
a valid skeleton instance and add the other stuff as applicable or
when he actually has it.

Rob
http://cbmc64.blogspot.com
 
R

Roedy Green

Now, when I am writing the Project class, how do I decide which and
which of such information go to the constructor(s)? It apparently
does not make sense to cram all of them into a single constructor,
right? And if we decide to have multiple constructors, what
information needs to be selected and put into which constructor?

One goal of a constructor is that when you are done the object should
be logically complete containing all mandatory fields. I don't like
logically incomplete objects floating around the universe. This is a
stylistic goal, not something built in to Java.

When constructors get too hairy, you can create constructors that
accept aux aggregate objects as parms. That way you avoid creating
objects that need more setter calls before they can be used.
 
R

Roedy Green

I merely repeat after Bloch, so I can't take the credit. Immutability
makes code easier to debug, because objects don't go changing on you.
It also makes objects fit well within frameworks like collections
(imagine putting something in a hash set, then changing its internal
state which gives it a different hashcode).

Immutable objects are much better behaved in multi-thread situations.
You can't get into trouble with two threads updating the same thread
at once, or one thread seeing an object half way through an update by
another. With immutability, thread interaction becomes relatively
mindless. With mutability, it becomes a black art.
 
M

Martin Gregorie

Rob said:
This is a good question.

What I've found works well is the constructor contains the minimal
amount to create a valid instance of the object with setters for the
other stuff.

If you know how the client code will be used this can be helpful. For
a small number of fields where the client has all the information at
hand when he creates the object then the constructor can specify
everything.
That works for me, but I'd add another rule: don't put anything in the
constructor that throws an exception that must be caught outside the new
object declaration. Violating this rule tends to cause scoping problems.
 
A

antonyliu2002

This is a good question.

What I've found works well is the constructor contains the minimal
amount to create a valid instance of the object with setters for the
other stuff.

If you know how the client code will be used this can be helpful. For
a small number of fields where the client has all the information at
hand when he creates the object then the constructor can specify
everything.

In the project example it is quite possible that at the time the
client needs to create a Project he may only have some of the data at
hand and will need to get the rest later. So I'd let the client create
a valid skeleton instance and add the other stuff as applicable or
when he actually has it.

Robhttp://cbmc64.blogspot.com

So, the idea is to put those most important features into the
constructor in a situation where one is flooded with a large number of
attributes.
 
J

Joshua Cranmer

I have always been wondering about this question: How do we decide
what should be put into the constructor?

For example, a Project class can have a lot of attributes, such as
ProjectID, ProjectName, ProjectManagerID, ProjectDescription,
ProjectObjective, ProjectProgramAreaID, ProjectStatus, ProjectFundID,
ProjectFundStatus, ProjectSchedule, etc.

Now, when I am writing the Project class, how do I decide which and
which of such information go to the constructor(s)? It apparently
does not make sense to cram all of them into a single constructor,
right? And if we decide to have multiple constructors, what
information needs to be selected and put into which constructor?

I am confused, please shed some light on this issue. Thank you.

I just found Norvig's Java Infrequently Answered Questions page earlier
today, and one of them is marginally relevant:

Q: I have a class with six instance variables, each of which could be
initialized or not. Should I write 64 constructors?
(Relevant parts of the answer)
2. Define setters that can be cascaded because they return this. That
is, define a setter for each instance variable, then use them after a
call to the default constructor:
[ code omitted ]
Pro: This is a reasonably simple and efficient approach. A similar idea
is discussed by Bjarne Stroustrop on page 156 of The Design and
Evolution of C++.
Con: You need to write all the little setters, they aren't
JavaBean-compliant (since they return this, not void), they don't work
if there are interactions between two values.

3. Use the default constructor for an anonymous sub-class with a
non-static initializer:

new C() {{ a = 1; c = 3; e = 5; }}

Pro: [...]
Con: [...] When I showed this to Guy Steele, he said "heh, heh! That's
pretty cute, all right, but I'm not sure I would advocate widespread
use..." As usual, Guy is right.

Full text of the question, answer, and whole IAQ is here:
http://norvig.com/java-iaq.html
 
L

Lew

Martin said:
That works for me, but I'd add another rule: don't put anything in the
constructor that throws an exception that must be caught outside the new
object declaration. Violating this rule tends to cause scoping problems.

I wouldn't add that rule. "Scoping" is totally not involved in exceptions
thrown from constructors; I really don't even know what you meant by that.

It's perfectly legitimate to throw an exception from a constructor.
 
M

Martin Gregorie

Lew said:
I wouldn't add that rule. "Scoping" is totally not involved in
exceptions thrown from constructors; I really don't even know what you
meant by that.
Maybe its a stylistic error on my part, but I like to put all
declarations at the head of a method and to keep try blocks as short as
possible. The requirement to wrap a declaration in a try block if it
throws exceptions tends to go against this style. In consequence, I move
the bits of a constructor that can throw exceptions into a method.

For instance, I have a Java class that's the equivalent of the C
getopt() function. I use it in command-line applications to parse the
command line, setting flags etc from options and building an array of
non-option arguments. The constructor merely captures the args[] array
together with the list of valid options and whether they take mandatory
or optional values. Parsing the args[] array can throw an exception if
it discovers invalid options, so its split out into a separate method.
This way I can localize it and the error exit in a small try block. Once
that's out of the way I can go on to deal with the lists of options and
non-options outside the try block because the methods for that
(nextOption() + getValue(), nextArgument()) don't throw exceptions but
may well control code that does throw completely unrelated exceptions of
their own: to me its cleaner to keep these two types of exceptions in
separate try blocks.
It's perfectly legitimate to throw an exception from a constructor.
Sure. I'm just suggesting that there are reasons for not doing so. I'll
be interested to hear your opinion of this reasoning.
 
L

Lew

Martin said:
Sure. I'm just suggesting that there are reasons for not doing so. I'll
be interested to hear your opinion of this reasoning.

Your reasoning is quite sound. I'd phrase the principles involved a little
differently, but I'd bet I'd come up with the same conclusions.

While I said that constructors can legitimately throw exceptions, I didn't say
they should, necessarily. Constructors should throw exceptions only if the in
the logic of construction it makes sense. For example, in your GetOpt class
I'd consider throwing an exception if args[] were null. That way the client
code finds out at the point of error that there was a problem. Throwing an
NPE in the process() method (or whatever you call it) is useful, but could
happen distant from the point of error, passing null to the constructor.

Then I'd likely reject that idea and treat null args the same as empty args,
i.e., no options.

But that's the kind of reasoning that might lead me to throw an exception from
a constructor. I admit I would resist it until compelled. What would compel
is a condition that must halt the program, like a Data Access Object (DAO) not
finding its datastore driver.

As for not processing args in the constructor, that's a different principle
for me. Constructors are for construction, period. Processing the args is
not part of constructing the object; passing them into an instance variable
is. Doing too much in a constructor is a mistake in its own right, and leads
to various kinds of trouble.

We converge in that the less one does in a constructor, the less excuse one
has to throw exceptions there. With the constructor's purpose clearly
understood and constrained, the kinds of things that can throw exceptions in
it tend to be excluded.
 
J

Joe Attardi

Martin said:
Sure. I'm just suggesting that there are reasons for not doing so. I'll
be interested to hear your opinion of this reasoning.

One particular instance I can think of is to throw an
IllegalArgumentException if arguments are passed that just don't make
any sense.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,780
Messages
2,569,611
Members
45,273
Latest member
DamonShoem

Latest Threads

Top