Re: passing a Factory to a method to create a generic instance
On Sun, 11 May 2008, Lew wrote:
Tom Anderson wrote:
Except it isn't, because the constructor doesn't have the information
it needs to create the object. Yes, it allocates memory for it and
clears its fields and runs the instance initialiser, but that's only
creation in a trivial sense. If i do Room.class.newInstance(), i have a
Room object, but i don't have a room - it doesn't have a number, a
floor, or a number of beds.
I know that in correct use, you'll go straight from instantiation to
initialisation, so the period of Room-that-is-not-a-room is vanishingly
small, and no danger can occur. The problem arises when the use is
incorrect, and uninitialised Rooms can escape to unwitting code. In our
discussion of operator overloading, you said "I like to design things
that can't fail" - where failure is completely impossible by design.
That's what i'm trying to get at here.
Where one absolutely must separate building an object from its
construction, I'm aware of two patterns, the Builder pattern (think
StringBuilder), often combined with the Factory pattern, and the
WhatchaMaCallIt pattern - throw IllegalStateException for any attempt to
operate an unbuilt object.
I had the latter in mind, but it hadn't occurred to me to use Builder
here. As Mark went on to expound, it offers a pretty straightforward way
of dealing with construction in this situation. Good idea.
Although the Factory option here is also straightforward.
The objections to every pattern so far proffered amount to the same
thing. There arise scenarios where initialization is just done well
after construction, and those scenarios carry risk that must be managed
through extra code and effort. Properly architected, that effort comes
at the root of the difficulty and not patched onto the surface.
Constructors really work best when limited to "only creation in a
trivial sense".
I'm not sure i agree with this. In fact, i'm sure i don't agree with this.
It turns out that jamming all the building phase into construction
carries risk, too, and that risk requires management through code and
effort. Unfortunately, many programs do not evince that care, and do
things like call overridable methods in the constructor of a class that
is intended as a base class, or create side effects from the constructor
that are hard to unroll if construction fails.
Good points.
I suspect it is easier to manage the risk of separate construction and
build phases than it is the risk of monolithic construction.
Which i suppose is the whole point of the Builder pattern!
What we have is a tension between an all-at-once interface to
construction, which gives us nice safety and certainty guarantees, but
puts a huge load on the user, and an incremental approach, which is
friendlier, but vulnerable to mistakes. The essence of the builder pattern
is that it lets us present one interface to the object and another one to
the user. It's effectively a large-scale Adapter pattern. Which should
really come as no surprise - see sig!
tom
--
Any problem in computer science can be solved with another layer of
indirection. -- David Wheeler