This is Part 2 of a 2 parts series on using a weak variant of the builder pattern with Java instead of using utility classes. This part discusses creating ASCII art using a builder. You may start off with Part 1 being on ASCII tables or go on with the article on Base64 encoding with builders.
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.
Don’t Panic, its easy! To get up and running, include the following dependency (without the three dots “…”) in your
1 2 3 4 5 6 7 8 9 <dependencies> ... <dependency> <artifactId>refcodes-textual</artifactId> <groupId>org.refcodes</groupId> <version>3.3.3</version> </dependency> ... </dependencies>
Part 2: Building ASCII art
The code snippet for the above
DON'T PANIC banner is straight forward: Create and configure your
AsciiArtBuilder and print out the text (“DON’T PANIC”):
Let us do the classic “Hello World!” example by tweaking the above code a little:
Here I changed the font and adjusted the
AsciiColorPalette to be used by the algorithm:
What about inverting the output?
Here I adjusted the
You may even use your own Palette. For the below example I used just tree “colors”:
The palette now consists of the three characters
# representing the range from bright to dark:
ASCII art from images
Just let the
in point to the image source of your choice (
AsciiArtBuilder can easily be extended without breaking the
API. For example we could skip the explicit creation of the
RgbPixmap and include the
RgbPixmapImageBuilder functionality in the
AsciiArtBuilder by adding the methods
The number of methods above would even double if we decided to provide the same functionality as above with the difference of returning a single
String with embedded line breaks instead of returning
String arrays where each element of the array represents one line.
For the weak
builder (also referred as
builder in this context) I just have to add the method
String toString( String aText ) in addition to the already existing
String toStrings( String aText ) method, no matter how many properties there are which I can configure for the
Also, extending a
utility class’s method with additional parameters would break the
API whereas for the
builder we just add the additional methods such as - staying with the
RgbPixmap example -
withImageUrl(...) and old code still keeps on working.
builderimplements one specific functionality, it is easily maintained and extended without resulting in hundreds of lines of complex code and dozens of
telescoping methods. Moreover, extending the
builderwith new functionality does not break your
APIas you would do by extending a
utility classwith additional arguments.
utility class should be thread safe and free of
race conditions as of its nature being stateless: All required information is passed to its methods by the according arguments. For the
AsciiArtBuilder to be thread safe and free of
race conditions I introduced the
toString( String aText ) method which avoids the text to be processed to be part of the
builder’s state. The configuration attributes are still matter of
race conditions, though having configured your
builder once, you can invoke its
toString( String aText ) method in parallel without the risk of any side effects.
buildershould provide means to execute its main concern without changing the
builderstate. Provide an execution method with those parameters to be passed which otherwise would bear a risk for side effects when they were representing state.
I do not consider the configuration properties to be passed as arguments for such an execution method. Though those values which will actually be digested by your
builder such as “Hello World!” and “DON’T PANIC” in the above example are to be considered as the main concern: For those properties provide means to execute the builder in a thread safe manner. You may even omit attributes for such arguments!
When regarding the aspects mentioned above then the creation of
builder instances should stay low - in case you do not need to invoke its functionality with ever changing configuration properties.
Readability and usability
utility class you might have to remember all the configuration parameters somewhere in your code in order to invoke the
utility class methods over and over again. This can bloat your code and make it unreadable and hard to focus on the actual task to be performed by your code. A
builder encapsulates these configuration parameters for you.
A nice side effect of such a
builderis that you easily find it with the type search of your
builderimplements one specific functionality and as its name reflects its functionality.
Utility-builder pattern - a definition
What we came up with looks to me very much like a
software design pattern. Let me try a definition in one sentence of what I will call the
utility-builder patternis 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 method as arguments) to the state of the
utility-builderinstance while providing a
thread safebuilder 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-builderclass and which must not be part of the state of the