Friday, February 10, 2006

Initialization Chain

Initialization Chain allows you to chain additional property setters to an object's initialization.
Column column = new Column().WithHeader("ID").WithType(typeof(int))
Initialization Chain is a special case of Fluent Interface. It's most often seen during testing, but it also has a place in production code.

Initialization Chain can be used to reduce the number of constructors of a class. In the above example a constructor of Column could be created to take both a header and column type. However, neither of these properties are dependencies of the class. Creating constructors that initialize properties that are not dependencies can lead to constructor bloat.

Initialization Chain is more expressive than using a constructor to initialize properties. When maintaining an existing codebase you will need to understand which properties are being set by which constructor arguments. Additionally, you will need to know which constructor arguments are dependencies and thus required across all constructors of the class. Initialization Chain will explicitly show that any argument of a constructor is a dependency and any additional properties that need to be set can be done in the chain by methods that express which property is being set.

Initialization Chain can remove the need for a temporary variable. In the above example an instance of the Column class is being initialized. Generally, this type of operation will occur in some type of loop. In general you will need to create each Column instance, set the properties, and add the new Column instance to the collection. Initialization Chain allows you to set the properties following construction and immediately pass the instance to the collection without the need for the temporary variable.

There are also negatives to Initialization Chain. Readonly fields cannot be initialized from an Initialization Chain. There is overhead in creating and maintaining the Initialization Chain methods. They can clutter the API by adding an additional method for each property. And, there is no stopping someone from using one long after initialization.

Implementing Initialization Chain is quite simple. For each property that you wish to be able to initialize in an Initialization Chain you must simply add a method that sets the property and then returns the instance.
class Foo...
public string Bar
{
get { return bar; }
set { bar = value; }
}

public Foo WithBar(string value)
{
Bar = value;
return this;
}

3 comments:

  1. Anonymous7:16 PM

    But is not actually the point of a constructor to set certain values which may NOT be changed during the lifecycle of an object? This can certainly not be implemented by this pattern: The WithXYZ methods can be called any time.

    ReplyDelete
  2. Anonymous8:06 PM

    Something that cannot be changed following construction is what I was referring to as readonly in the first of the negatives concerning Initialization Chain.

    You are correct, these arguments belong in a constructor, not in a Initialization Chain.

    ReplyDelete
  3. Anonymous9:52 PM

    Oh, so *that's* what it's called, huh? Been using it somewhat frequently recently on our project.

    1) Didn't know it was called "Initialization Chain".
    2) Didn't know it was a special case of a FluentInterface.

    Hmm.

    ReplyDelete

Note: Only a member of this blog may post a comment.