This is part 2 of a two 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.
Part 2: ASCII art
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.
Do you have some command line Java tools not being enriched with some fancy
ASCII art
? It’s likeBash
scripting and not usingFIGlet
;-)
Don’t Panic, its easy! To get up and running, include the following dependency (without the three dots “…”) in your pom.xml
:
1
2
3
4
5
6
7
8
9
<dependencies>
...
<dependency>
<artifactId>refcodes-textual</artifactId>
<groupId>org.refcodes</groupId>
<version>3.3.8</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 AsciiArtMode
…
You may even use your own Palette. For the below example I used just tree “colors”:
The palette now consists of the three characters .
, /
and #
representing the range from bright to dark:
There is another feature the AsciiArtBuilder
supports which should not stay unmentioned: Creating ASCII art
from images such as .png
, .gif
or .jpg
:
ASCII art from images
You can also pump an image through the AsciiArtBuilder
by passing a RgbPixmap
from an InputStream
:
Here I used the REFCODES.ORG
logo retrieved from an InputStream
by the RgbPixmap
which is being passed to the AsciiArtBuilder
:
Just let the InputStream
variable in
point to the image source of your choice (.png
, .gif
or .jpg
).
Reflection
Now let us take a a look at and compare the builder pattern
with utility classes
:
Extensibility
The 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 withImageInputStream(...)
and withImageUrl(...)
A utility class
on the other hand might provide the following methods in order to provide the same functionality such as that of the AsciiArtBuilder
:
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 builder
.
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 - withImageInputStream(...)
and withImageUrl(...)
and old code still keeps on working.
As one
builder
implements one specific functionality, it is easily maintained and extended without resulting in hundreds of lines of complex code and dozens oftelescoping methods
. Moreover, extending thebuilder
with new functionality does not break yourAPI
as you would do by extending amethod
of autility class
with additional arguments.
Thread safety
A 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.
Your
builder
should provide means to execute its main concern without changing thebuilder
state. 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!
Resource consumption
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
For a 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
builder
is that you easily find it with the type search of yourIDE
as onebuilder
implements 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 pattern
:
The
utility-builder pattern
is characterized by providing the functionality of autility class
(or parts of it) being implemented with the means of thebuilder pattern
, thereby moving configuration (and the like) concerns (otherwise passed to theutility class
’s method as arguments) to the state of theutility-builder
instance while providing athread safe
builder method for constructing theutility-builder
’s concern which only takes those argument(s) being passed which are directly related to the concern of theutility-builder
class and which must not be part of the state of theutility-builder
’s instances.
Resources
The source codes of the refcodes-textual
artifact is found at bitbucket.org
.
Further reading
Continue with part q which discusses creating ASCII tables using a builder.