Composable Decorators vs. Imperative Utility Methods

The decorator pattern
is my favorite among all other patterns I'm aware of. It is a very simple
and yet very powerful mechanism to make your code
highly cohesive and
loosely coupled.
However, I believe decorators are not used often enough. They should
be everywhere, but they are not. The biggest advantage we get from decorators
is that they make our code composable. That's why the title of this
post is composable decorators. Unfortunately, instead of decorators, we often use imperative
utility methods, which make our code procedural rather than object-oriented.

First, a practical example. Here is an interface for an object that is
supposed to read a text somewhere and return it:

As you can see, the PrintableText doesn't read the text from the file. It doesn't
really care where the text is coming from. It delegates text reading to
the encapsulated instance of Text. How this encapsulated object will
deal with the text and where it will get it doesn't concern PrintableText.

Let's continue
and try to create an implementation of Text
that will capitalize all letters in the text:

I can go on and on with these
decorators.
I can create many of them,
suitable for their own individual use cases. But let's see how they all
can play together. Let's say I want to read the text from the file,
capitalize it, trim it, and remove all unprintable characters. And I want
to be declarative. Here is what I do:

First, I create an instance of Text, composing multiple decorators into
a single object. I declaratively define the behavior of text without
actually executing anything. Until method read() is called, the file is not touched
and the processing of the text is not started. The object text is just
a composition of decorators, not an executable procedure. Check out this
article about declarative and imperative styles of programming:
Utility Classes Have Nothing to Do With Functional Programming.

This design is much more flexible and reusable than a more traditional one,
where the Text object is smart enough to perform all said operations. For
example, class String
from Java is a good example of a bad design. It has
more than 20 utility methods that should have been provided as decorators instead: trim(), toUpperCase(), substring(), split(), and many others, for example.
When I want to trim my string, uppercase it, and then split it into pieces,
here is what my code will look like:

This is imperative and procedural programming. Composable decorators,
on the other hand, would make this code object-oriented and declarative. Something
like this would be great to have in Java instead (pseudo-code):

final String[] parts = new String.Split(
new String.UpperCased(
new String.Trimmed("hello, world!")
)
);

To conclude, I recommend you think twice every time you add
a new utility method to the interface/class. Try to avoid utility methods as much
as possible, and use decorators instead. An
ideal interface should contain
only methods that you absolutely cannot remove. Everything else should be
done through composable decorators.