Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / August 2007

Tip: Looking for answers? Try searching our database.

OO Design: What goes into the constructor?

Thread view: 
antonyliu2002@yahoo.com - 09 Aug 2007 15:29 GMT
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.
tzvika.barenholz@gmail.com - 09 Aug 2007 16:36 GMT
On Aug 9, 5:29 pm, "antonyliu2...@yahoo.com" <antonyliu2...@yahoo.com>
wrote:
> I have always been wondering about this question: How do we decide
> what should be put into the constructor?
[quoted text clipped - 11 lines]
>
> 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
Joe Attardi - 09 Aug 2007 16:59 GMT
> 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?

Signature

Joe Attardi
jattardi@gmail.com

tzvika.barenholz@gmail.com - 09 Aug 2007 17:44 GMT
> tzvika.barenh...@gmail.com wrote:
> > 1. It's generally a good idea to make objects immutable, and put
[quoted text clipped - 6 lines]
> Joe Attardi
> jatta...@gmail.com

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
kaldrenon - 09 Aug 2007 18:09 GMT
On Aug 9, 12:44 pm, "tzvika.barenh...@gmail.com"
<tzvika.barenh...@gmail.com> wrote:
> 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?
Roedy Green - 09 Aug 2007 19:49 GMT
On Thu, 09 Aug 2007 16:44:39 -0000, "tzvika.barenholz@gmail.com"
<tzvika.barenholz@gmail.com> wrote, quoted or indirectly quoted
someone who said :

>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.
Signature

Roedy Green Canadian Mind Products
The Java Glossary
http://mindprod.com

Thomas Hawtin - 09 Aug 2007 17:19 GMT
> 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
antonyliu2002@yahoo.com - 09 Aug 2007 17:30 GMT
> tzvika.barenh...@gmail.com wrote:
>
[quoted text clipped - 22 lines]
>
> Tom Hawtin

Tom, are those dotted identifiers (.id, .name, .description, etc.)
setter methods?  I am confused by the syntax.
Chris Riesbeck - 09 Aug 2007 19:07 GMT
>> tzvika.barenh...@gmail.com wrote:
>>
[quoted text clipped - 24 lines]
> 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.
Wojtek - 09 Aug 2007 19:19 GMT
Chris Riesbeck wrote :
>>> tzvika.barenh...@gmail.com wrote:
>>>
[quoted text clipped - 40 lines]
> 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();

Signature

Wojtek :-)

antonyliu2002@yahoo.com - 09 Aug 2007 17:26 GMT
On Aug 9, 11:36 am, "tzvika.barenh...@gmail.com"
<tzvika.barenh...@gmail.com> wrote:
> On Aug 9, 5:29 pm, "antonyliu2...@yahoo.com" <antonyliu2...@yahoo.com>
> wrote:
[quoted text clipped - 30 lines]
>
> 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?
Rob - 09 Aug 2007 19:34 GMT
On Aug 9, 11:29 am, "antonyliu2...@yahoo.com"
<antonyliu2...@yahoo.com> wrote:
> I have always been wondering about this question: How do we decide
> what should be put into the constructor?
[quoted text clipped - 11 lines]
>
> 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
Martin Gregorie - 10 Aug 2007 01:02 GMT
> On Aug 9, 11:29 am, "antonyliu2...@yahoo.com"
> <antonyliu2...@yahoo.com> wrote:
[quoted text clipped - 23 lines]
> 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.

Signature

martin@   | Martin Gregorie
gregorie. | Essex, UK
org       |

Lew - 15 Aug 2007 13:01 GMT
> 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.

Signature

Lew

Martin Gregorie - 16 Aug 2007 11:59 GMT
>> 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
[quoted text clipped - 4 lines]
> 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.

Signature

martin@   | Martin Gregorie
gregorie. | Essex, UK
org       |

Lew - 16 Aug 2007 12:58 GMT
Lew wrote:
>> 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.

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.

Signature

Lew

Martin Gregorie - 17 Aug 2007 00:16 GMT
> 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.

I've come to Java from C with almost no formal background or training in
OOD techniques. In C I've developed a personal pseudo-OO style that just
growed because it minimizes bad interactions. In it I store variables as
control-block structs (very similar to the way that the FILE struct is
used) or as globals with their scope limited to the source file if
there's never more than one "instance" possible per program. All access
to these variables are solely via functions. I also write functions
equivalent to constructor and destructor. The major difference is that,
because the constructor function can return a status code, I'll often do
the equivalent of parsing the option definition string within it. I
think its arguable whether that counts as part of initialization: my
conclusion has been that in C the constructor is a good place to put it
but in Java its often better to split it out.

This seemed like a good place in the thread to check whether this is
sensible, so thanks for your feedback.

> While I said that constructors can legitimately throw exceptions, I
> didn't say they should, necessarily.

I assumed that was what you meant.

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

Which is exactly what it does    :-)

I also use setters to handle seldom used options rather than multiple
constructors. An example would be to turn option case sensitivity on
(default is off).

Signature

martin@   | Martin Gregorie
gregorie. | Essex, UK
org       |

Joe Attardi - 16 Aug 2007 15:56 GMT
> 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.

Signature

Joe Attardi
jattardi@gmail.com

Martin Gregorie - 17 Aug 2007 00:23 GMT
>> 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.

Agreed, though validation generally requires more processing than
I'd now do in the constructor. I'm with Lew here. Also, suitable
choice of parameters (using booleans in place of ints or strings
and/or passing appropriate classes) can hand off quite a bit of simple
validation to the compiler.

Signature

martin@   | Martin Gregorie
gregorie. | Essex, UK
org       |

antonyliu2002@yahoo.com - 10 Aug 2007 16:04 GMT
> On Aug 9, 11:29 am, "antonyliu2...@yahoo.com"
>
[quoted text clipped - 33 lines]
>
> 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.
Roedy Green - 09 Aug 2007 19:46 GMT
On Thu, 09 Aug 2007 14:29:13 -0000, "antonyliu2002@yahoo.com"
<antonyliu2002@yahoo.com> wrote, quoted or indirectly quoted someone
who said :

>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.
Signature

Roedy Green Canadian Mind Products
The Java Glossary
http://mindprod.com

Joshua Cranmer - 10 Aug 2007 23:01 GMT
> I have always been wondering about this question: How do we decide
> what should be put into the constructor?
[quoted text clipped - 11 lines]
>
> 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

Signature

Beware of bugs in the above code; I have only proved it correct, not
tried it. -- Donald E. Knuth



Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.