Combining a Utility classs functionality with a weak variant of 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. Lets try a definition…
In this context, a weak builder
or a weak variant of the builder pattern is considered to combine the builder pattern with the subject of interest into a single object, e.g. the actual functionality is enriched with builder
functionality instead of separating the builder
functionality from the functionality of interest.
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.
… 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
. Thetelescoping constructor
anti-pattern
occurs when the increase of objectconstructor parameter
combination leads to an exponential list ofconstructors
… (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 relatedarguments
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 asarguments
in themethod
executing (building) the utility-builder’s main concern. The directly relatedarguments
do not belong to the state of the utility-builder in order to enablethread safe
invocation of the same instance of a utility-builder with varying directly relatedarguments
.
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
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 implementationUtilityProduct
: The result of the process (build) functionality when invoking the UtilityBuilder
Collaboration
- The
Director
instantiates an implementation of choice of the UtilityBuilder such as theConcreteUtilityBuilder
. TheDirector
can switch to another implementation as its business logic is coupled to the UtilityBuilder interface and not to a concrete implementation. - Then the
Director
may changes the state of the UtilityBuilder as required by callingwithProperty( ... )
andwithAntoherProperty( ... )
, as of sound initial state, this step may be skipped. - The
Director
applies thebuild-utility
’s process (build) functionality by invoking thebuildUtilityConcern( ... )
method on the providedUtilityVariant
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 (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 AsciiArtBuilder
class:
Concern’s indirectly related arguments
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 );
Concern’s directly related arguments
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 AsciiArtBuilder().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
- Good bye utility classes, here come builders (1)
- Good bye utility classes, here come builders (2)
- Base! How low can you go? Base64, Base63, Base62, …
TableBuilder
AsciiArtBuilder
BaseBuilder