Core Java

Transforming Collections with Decorators

The Decorator Pattern

Ever since first learning the programming design patterns, the decorator pattern has been my favorite. It seemed such a novel idea to me, and so much more interesting than the others. Don’t get me wrong, most of the others blew my mind too, but none so much as the decorator pattern. To this day, it’s still one of my favorites.

(If you’re unfamiliar with design patterns, I highly recommend Head First Design Patterns. If you just want to learn about the decorator pattern, here is an excerpt of the decorator chapter from that book.)

Personally, I believe the decorator pattern is generally underutilized. There’s a couple probably reasons for this. For one, I don’t think it applies to all that many situations. Another thing, problems that can be solved with the decorator pattern are generally fairly difficult to spot. What makes the pattern so mind-blowing to me is the same reason it can be difficult to figure out where it’s needed, that reason being that it’s such an unusual idea. That is, it seems to be until you’re strongly acquainted with the principle of “composition over inheritance”.

So many places drill inheritance into your head so much that it’s really difficult for the mind to believe that composition can often be a better idea than inheritance.

Anyway, not only is the decorator pattern my favorite pattern, it’s strongly used in one my favorite new features of Java 8: the Stream API. In fact, much of what I’m going to show you largely mimics some of the behavior of the Stream API.

The Problem

Let’s say you have a list of Strings, but they may or may not have leading or trailing spaces that you don’t want. You’d probably do something like this to get rid of the unwanted spaces.

List untrimmedStrings = aListOfStrings();
List trimmedStrings = new ArrayList();

for(String untrimmedString : untrimmedStrings)
{
    trimmedStrings.add(untrimmedString.trim());
}

//use trimmed strings...

In this case, you create a whole new list of Strings and fill it with the Strings from the first list, but trimmed. There are several problems with this. First off, it creates an entire new list right off the bat. Instead, the creation of each trimmed String could be delayed until needed, and never even be done if it isn’t needed. Also, if someone wanted to add more Strings, you’d have to add them to both lists. You’d also have to make sure you trim the new Strings before putting them into the trimmed list. Lastly, this code is imperative instead of declarative.

Let’s look at a more declarative version of the code, then see how to use it to solve the other problems.

List untrimmedStrings = aListOfStrings();
List trimmedStrings = trimmed(untrimmedStrings);

//use trimmed strings...

Heck, anything could be happening in that trimmed() function! And look at that; it returns a list of Strings, just like the previous way. Fat load of good that did, right?

Wrong. Yes, that function could technically just be doing the same thing we did earlier, which means all we did was make this outer code declarative. But in this example, it is intended to be a static factory method (with a static import) that creates a new Trimmed object that wraps the untrimmedStrings list. Trimmed implements the List interface, but it delegates nearly everything to the wrapped list, but often with decorated functionality. When a new String is added or removed, it’s done to “both” lists by doing it to the wrapped list. And when it adds the new String, it can add it as-is, but then it simply needs to make sure that it’s trimmed on the way out.

Also, since trimming is only done when pulling data from the list, we didn’t have to do all the work of trimming every String right away. There’s a chance that some of the Strings will never even be dealt with, thus those String will never be needlessly trimmed.

There are some downsides to this, though. One, if the trimmed String is pulled from the list multiple times, it ends up getting trimmed every time. This doesn’t take any additional memory, but it does add a bit of time, especially if you loop over the entire list several times. Secondly, it creates the sort of side effect of the trimmed list and untrimmed list being the same list. A change to one affects the other, whether we want that or not.

I don’t want to waste too much time and space in this article to show you a fully created List implementation of Trimmed (there are over 30 methods to define for List), so I’m going to tweak it so that it’s just the Iterable methods that are defined. Since, a lot of the time, all you really do is iterate over collections, this will have to be relatively acceptable.

public class Trimmed implements Iterable
{
   public static List trimmed(List base) {
      return base;
   }

   public Trimmed(Iterable base)
   {
      this.base = base;
   }

   public Iterator iterator()
   {
      return new TrimmedIterator(base.iterator());
   }

   private Iterable base;
}

class TrimmedIterator implements Iterator
{
   public TrimmedIterator(Iterator base)
   {
      this.base = base;
   }

   public boolean hasNext()
   {
      return base.hasNext();
   }

   public String next()
   {
      return base.next().trim();
   }

   public void remove()
   {
      throw new UnsupportedOperationException();
   }

   private Iterator base;
}

How To Decorate Objects

I don’t recall anyone ever mentioning this anywhere, but it’s fairly important, so I want to tell you about it.

There are 2 basic schools of thought for how to decorate an object. The first is when you simply create a new instance of the decorator with the decorated/wrapped object passed in. The second option is to call a method on the object to be decorated.

Both options are shown here

MyCollection untrimmedStrings = aCollectionOfStrings();

//new Decorator Instance
MyCollection trimmedStrings = new TrimmingDecorator(untrimmedStrings);

//OR

//method call on the to-be-decorated object
MyCollection trimmedStrings2 = untrimmedStrings.trimmed();

And the code of trimmed() looks like this:

public MyCollection trimmed() {
   return new TrimmingDecorator(this);
}

Either way has its pros and cons. Since each options’ cons are essentially the lack of the other option’s pros, I’ll just list each option’s pros.

New Instance Pros:

  • More extensible than method call option, since the method calls have to try to cover every possibility of decorator
  • Users can see that it’s the decorator pattern more easily
  • Fewer methods required in the Decoratable interface

Method Call Pros:

  • Hides the decorator implementation if the user has no need to know
  • No explicit “new” keywords on the user end (which is generally considered bad)
  • Users have an easier time finding all of the decorators, since they’re all listed there on the decoratable object’s interface

Java’s original IO library is a good example of new instance decorating while the Stream API in Java 8 is a good example of method call decorating. My personal preference is to use the method call option, since it makes all the possibilities obvious to the user, but if the point is to make it so the user can extend your objects with their own decorators, too, then you should definitely go with the new instance route.

Jacob Zimmerman

Jacob is a certified Java programmer (level 1) and Python enthusiast. He loves to solve large problems with programming and considers himself pretty good at design.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
SkorpEN
SkorpEN
9 years ago
Back to top button