Pattern Patter
| Split Allocation and Initialization |
May, 1998 |
| Separate allocation and initialization: provide
them as separate operations rather than as a joint operation.
[Low-level Design Pattern] |
Context
You're creating an object based on an external data structure. Part
of the job is to create your object, and part is to populate it
with the information from the external structure.
Forces
- We want to allocate and initialize at the same time, as it can
be easier to allocate just the right space if we know how big the
initialization will be.
- The allocation process may change independently of the
initialization.
- The external structure may change independently of the
structure we're creating.
Resolution
Split allocation from initialization. That is, don't provide a
constructor like this:
public Form(Data data){...} //BAD
Instead, split this into a constructor and a "setter" method:
public Form() {...} //GOOD
public setData(Data data) {...}
(You may include the original constructor as a convenience method.
It should just call the "good" form.)
Discussion
While the desire to use initialization information to guide
allocation is understandable, the other forces should not be
ignored. They tend to show up later, after the first form has been
committed to.
Change in allocation policy: If you want to change how the form
is created (e.g., from a different pool), coupling the
initialization to the allocation will interfere with that
change.
Change in external structure: The structure of the internal data
structure shouldn't be highly coupled to the external structure.
(For example, in populating a form, you will find that you might
want to change the look of the form without changing the way it's
populated from the external data structure.)
Examples
- Building a form. We were creating a form that was to be
populated from CORBA structure. Later in development, it turned out
that we might want to re-populate the existing form (perhaps from a
refresh in the structure). The original design only lets you
populate it once: during initialization. Further, the form's
appearance would change (fields would change size, borders would be
added, etc.), but the "appearance" code was intermingled with the
"population" code. Splitting the constructor helped isolate the
concerns.
- NextStep. Their version of Objective-C (a Smalltalk-like
extension to C) used the form [Class new: data]. By
modifying it to become [[Class alloc] init: data], they
could change the allocation policy (providing for allocation from
separate pools), and they were better able to support remote
objects.
- Java Beans. The Java Beans model provides components for Java.
To be a bean, a class must provide a no-argument constructor, and
be Serializable. When a bean is instantiated, it is created by that
constructor, and then populated from its serialized form.
Related Patterns
- Parnas suggested the rule of having each module/routine have a
"secret", the design decision it encapsulates. This pattern pushes
a design more in that direction.
[Written 4-29-98]
|