The utility-builder pattern

The utility-builder pattern

Combining a Utility class’s functionality with the builder pattern, add some spicy properties to it, and here comes the utility-builder pattern. Utility classes are the container for lots of useful but lost code. Hard to find and hard to extend. The utility-builder (aka tool-builder) pattern provides relief. Let’s try a definition…

The utility-builder pattern is characterized by providing the functionality of a utility class (or parts of it) being implemented with the means of the builder pattern, thereby moving configuration (and the like) concerns (otherwise passed to the utility class’s utility method) to the state of the utility-builder instance while providing a thread safe builder method for constructing the utility-builder’s concern which only takes those argument(s) being passed which are directly related to the concern of the utility-builder class and which must not be part of the state of the utility-builder’s instances.

What the heck …

… wow, what the heck do I mean?!? In terms of software design patterns the utility-builder pattern seems to belong to the creational patterns as it borrows from the builder pattern to replace the classic utility class at least in some cases.

OK, this did not help very much? Then let’s go for the commonly accepted structure on describing software design patterns:

Utility-builder pattern

Intent:

The goal of the utility-builder pattern is to provide an extensible and maintainable alternative for implementrating functionality otherwise being placed inside utility classes. It also aims on transforming utility classes’ functionality into an API in terms of maintainability and extensibility. The utility-builder pattern is to solve the problem of breaking an API when extending utility classes.

Also Known As:

  • tool-builder pattern

Motivation (Forces):

… a utility class is a class that defines a set of methods that perform common, often re-used functions. Most utility classes define these common methods under static … scope …” (see Utility class)

When filling up utility classes with functionality, some such methods seem to be cluttered with arguments to make the desired functionality really generic resulting in telescoping methods. Which in turn makes the maintenance of such methods error prone and their use tiresome:

Which arguments are mandatory? Which arguments are optional? Which are the best default values for optional arguments?

Sometimes utility classes end up with the same method implemented various times with differing sets of arguments passed. Just to cover any possible and impossible usage scenario.

… the intention of the builder pattern is to find a solution to the telescoping constructor anti-pattern. The telescoping constructor anti-pattern occurs when the increase of object constructor parameter combination leads to an exponential list of constructors (see Builder pattern)

The utility-builder pattern applies the problem of telescoping constructors to the problem of telescoping methods common to utility classes.

Given the observation that arguments of utility classes’s methods often can be classified to be belonging either directly or indirectly to that method’s concern:

  • The indirectly related arguments are pushed to the state of a utility-builder. Only the indirectly related arguments are represented as state of the utility-builder, being initialized with sound defaults in terms of convention over configuration whilst being modified as of the builder pattern.
  • The directly related arguments reside as arguments in the method executing (building) the utility-builder’s main concern. The directly related arguments do not belong to the state of the utility-builder in order to enable thread safe invocation of the same instance of a utility-builder with varying directly related arguments.

Problem

Given a utility class to print out ASCII art. To reflect all kinds of initial requirements, we may have a method as follows:

String toAsciiArt( String aText, int aWidth, String aFontName, int aFontStyle, int aFontSize ) { ... }

A requirement arises to change the color palette to be used when printing out the ASCII art. The above method may be extended with an an additional argument as follows:

String toAsciiArt( String aText, int aWidth, String aFontName, int aFontStyle, int aFontSize, char[] aPalette ) { ... }

As this breaks the API, the method may just be overloaded resulting in two similar methods:

String toAsciiArt( String aText, int aWidth, String aFontName, int aFontStyle, int aFontSize ) { ... }
String toAsciiArt( String aText, int aWidth, String aFontName, int aFontStyle, int aFontSize, char[] aPalette ) { ... }

Solution

Applying the utility-builder pattern to an AsciiArtBuilder, we solve the problem with the following software design:

AsciiArtBuilder withWidth( int aWidth );
AsciiArtBuilder withFontName( String aFontName );
AsciiArtBuilder withFontStyle( int aFontStyle );
AsciiArtBuilder withFontSize( int aFontSize );
AsciiArtBuilder withPalette( char[] aPalette );
String toAsciiArt( String aText ); // build the utility's concern

Extending the above AsciiArtBuilder with new configuration properties (concern’s indirectly related arguments) does not break any API, the configuration properties are part of the state and do not need to be carried around by the code using the AsciiArtBuilder. The concern’s directly related arguments are passed to the actually executing (building) method avoiding side effects when being invoked by multiple threads simultaneously.

Applicability:

The utility-builder can be applied whenever a utility class functionality is to be implemented in a maintainable and reusable way to guarantee stability of your API.

Structure:

Utility-builder pattern (UML)

Participants:

  • Director: The client using the UtilityBuilder
  • UtilityBuilder: An interface defining the utility-builder’s functionality
  • ConcreteUtilityBuilder: A concrete implementation of the UtilityBuilder, there may be more than one implementation
  • UtilityProduct: The result of the process (build) functionality when invoking the UtilityBuilder

Collaboration:

  1. The Director instantiates an implementation of choice of the UtilityBuilder such as the ConcreteUtilityBuilder. The Director can switch to another implementation as its business logic is coupled to the UtilityBuilder interface and not to a concrete implementation.
  2. Then the Director may changes the state of the UtilityBuilder as required by calling withProperty( ... ) and withAntoherProperty( ... ), as of sound initial state, this step may be skipped.
  3. The Director applies the build-utility’s process (build) functionality by invoking the buildUtilityConcern( ... ) method on the provided UtilityVariant argument with regard to its state.

Consequences:

Extensibility

As a utility-builder implements one specific functionality, it is easily maintained and extended without resulting in hundreds of lines of complex code and dozens of telescoping methods common to utility class. Extending a utility-builder with new functionality does not break the API as you would do by extending a method of a utility class with additional arguments.

Thread safety

As a utility-builder provides means to execute its main concern without changing the utility-builder’s state, a utility-builder is thread safe as long as the configuration of the utility-builder is not changed. Changing the configuration still bears a risk for side effects as they are representing state.

Resource consumption

When regarding the aspects mentioned above then the creation of utility-builder instances should stay low in case you do not need to invoke its functionality with ever changing configuration properties.

Readability and usability

For a utility class with telescoping methods one has to remember all the configuration parameters somewhere in the code in order to invoke the utility class methods over and over again. This can bloat the code and make it unreadable and hard to focus on the actual task to be performed by the code. A utility-builder encapsulates these configuration parameters for you.

A utility-builder can be easily found with the type search of a modern IDE as one utility-builder implements one specific functionality and as its name reflects its functionality.

Implementation:

Sticking to the ASCII art example, consider an AsciiArtBuilder which can be used to print out text with a given font rendered by using ASCII characters (and the like) instead of color pixels when printing the banner (see Good bye utility classes, here come builders (part 2). See this banner for an example printing the text DONT'T PANIC in ASCII art.

The utility-builder is defined by the AsciiArtBuilder interface, a default implementation is represented by the AsciiArtBuilderImpl class:

The implementation of the utility-builder pattern moves the configuration arguments (aka the concern’s indirectly related arguments) to the state of the AsciiArtBuilder implementation. This results in the according member variables:

int width = 80;                            // pre-configured width in chars of the ASCII art banner
String fontName = "courier";               // pre-configured font name to be used by the ASCII art banner
int fontStyle = 2;                         // pre-configured font style (italic) to be used by the ASCII art banner
int fontSize = 12;                         // pre-configured font size to be used by the ASCII art banner
char[] aPalette = ' ', '░', '▒', '▓', '█'; // pre-configured "color" palette to be used

Ther according methods look as follows:

AsciiArtBuilder withWidth( int aWidth );
AsciiArtBuilder withFontName( String aFontName );
AsciiArtBuilder withFontStyle( int aFontStyle );
AsciiArtBuilder withFontSize( int aFontSize );
AsciiArtBuilder withPalette( char[] aPalette );

The concern’s directly related arguments are passed to the executing (building) method of the AsciiArtBuilder, here it is the text to be printed as ASCII art:

String[] toStrings( String... aText ); // build the build-utilitie's concern: render the text as ASCII art

Sample Code:

Using the AsciiArtBuilder may look as follows:

AsciiArtBuilder builder = new AsciiArtBuilderImpl().withFontType( "DialogInput" ).withFontSize( 12 ); // just adjust what is necessary
String[] lines = builder.toStrings( "DONT'T PANIC" );                                                 // create your banner in a thread safe manner
lines = builder.toStrings( "And thanks for the fish!" );                                              // create another banner without side effects

Known Uses:

Related Patterns:

comments powered by Disqus