cft

Design Patterns Saga: The Cabbage

Overview of Decorator Design Pattern


user

Gene Zeiniss

3 years ago | 6 min read

I was born in the city, located on the western bank of the Amur River in the Russian Far East. This area is known for its humid continental climate, which is typified by large seasonal temperature differences. Huge differences! The winters there were very cold. Sometimes temperatures fell to -40℃.

One of my most vivid memories of the Russian winter was the dressing up process before you step outdoors. I can describe it in one word: layers. And in a few words: a lot of layers. Countless. It was like, leggings over the cotton warm tights, and wool socks over both. Then the sweater over the shirt.

Then, wool mittens, connected by a long rubber band, so they don’t get lost, and a thin knitted cap. Now, comes the outer layer, that includes a fur coat and a fur hat (that you put over the cap you wore previously), and valenki ( traditional Russian felt boots, mine were with stitched initials). And that’s not all. The coat, hat, and your face are wrapped by a wool scarf. So only your eyes were exposed. Voila, it’s about time you got ready!

We in the business named this method of dressing: “Layered Clothing”. Catchy and descriptive. I take it a step forward and call it “cabbage” (just try to imagine it). This is my real-life example of the Decorator Design Pattern. We are going to face this pattern shortly. Let’s warm-up it by a regular “What do we know about anything?” column. Today’s topic is aggregation.

What Do We Know About Aggregation?

Cambridge dictionary says that “aggregation is a process of combining things or amounts into a single group or total”. One of the synonyms of aggregation is “heap”, and heap, according to the same source, is “an untidy pile or mass of things”. I’m pretty ok with this definition. There is just one thing that ruins it for me. If aggregation is a process and the heap (an untidy heap) is a result of the process, why are these two words synonymous?

Abstraction in Java in a Few Words

In Java Aggregation is more straightforward. It’s a relationship between classes represented by one-way association. Such as, “you show me yours” (but I’ll not show you mine 😜 ). Heap is the embodiment of aggregation. A thing can exist without a heap, but a heap without things is … nothing!

Take a look. This is a Thing object. It has a type and the name. And it can exist as is.

@Builder
public class Thing {
String type;
String name;
}

Here is a heap. It has a height (big heap / huge…) and location, but it can’t exist without things.

@Data
public class Heap {
private String height;
private String location;
private List<Thing> thing;
}

Only when you have things, for example, clothes, can you create a heap of clothes. Peel off your layers and throw them untidy to the floor 😉!

public Heap createHeapOfClothes() {
Heap heap = new Heap();
heap.setHeight("huge");
heap.setLocation("on the bathroom floor");
heap.setThing(Arrays.asList(
Thing.builder().type("clothes").name("t-shirt").build(),
Thing.builder().type("clothes").name("jeans").build(),
Thing.builder().type("clothes").name("right sock").build(),
Thing.builder().type("clothes").name("left sock").build()));
return heap;
}

I didn’t just bring up aggregation. The Decorator Pattern uses aggregation to combine behaviors at runtime.

If you didn’t read the previous Design Patterns Saga chapter, this is a good time to do so. We will use the same examples and will share the code. Briefly, I described the way to prepare season outfits for Tanja (a paper doll), using the Template Method pattern.

To implement it, we created the Outfit abstract class that declared methods that describe the steps that create a daily look. Some of the steps were declared as abstract (e.g. describeTop(), describeBottom(), describeFootwear()), others had a default implementation (e.g. drawDescribedOutfit(), cutDrawnOutfit()). It also defines the actual template method createDailyLook(). This method strung the step methods in a daily outfit creation algorithm.

The current challenge is to add outerwear to the outfit dynamically, without changing base-class definitions. Can you think of a solution? I whisper “layers”, but you should hear “Decorator Pattern”.

Decorator Pattern

The following quote was taken from Wikipedia:

Decorator Pattern is a design pattern that allows behavior to be added to an individual object, dynamically, without affecting the behavior of other objects from the same class.

Exactly our case! It’s a structural pattern that extends the object’s behavior by constructing a wrapper around it. Think about layered clothing. Each layer is a decorator, wrapping the previous layer.

Original image from The Cut.com, Debuts, August 2012. Photoshop by Tatyana Zeiniss ❤️

Let’s consider adding outerwear to Tanja’s outfit data-diagram.

Alright, here’s what you got. The left side of the diagram remains unchanged. Abstract Outfit class includes a template method. Concrete outfit classes extend the base-class and can be instantiated. An instance of these concrete classes is an original outfit that will be decorated afterward.

Now, let’s review the right side. The Outerwear Decorator is an abstract class. Just like the Autumn Outfit and Summer Outfit classes, it extends the base Outfit class. The main differences are that the decorator aggregates other types of components that will allow layers to be added. The decorator sub-class, Coat Decorator adds a new outwear layer on top of the previous outfit layers.

I hope it makes a little bit of sense. Let’s see the code example, to make it clearer.

Decorator Pattern Implementation

You already have the Autumn Outfit implemented from the Template Method example. This is your basic outfit.

public class AutumnOutfit extends Outfit {
@Override
public void describeTop() { log.info("white sweater"); }
@Override
public void describeBottom() { log.info("ripped jeans"); }
@Override
public void describeFootwear() { log.info("veja sneakers"); }
}

Now, you need an Outwear Decorator to add more garments to your basic outfit using aggregation. You will need to use the sub-class of the abstract decorator class to add to a basic outfit. As we explored earlier, the Outwear Decorator is a sub-class of an Outfit. Therefore, a concrete decorator is also a sub-class of the Outfit.

@RequiredArgsConstructor
public abstract class OuterwearDecorator extends Outfit {

public abstract void describeOuterwear();

@Override
public void createDailyLook() {
describeTop();
describeBottom();
describeFootwear();
describeOuterwear();
drawDescribedOutfit();
cutDrawnOutfit();
}
}

The base decorator holds new abstract behavior describeOuterwear(), that will be implemented by the concrete decorator. And, it overrides the createDailyLook() method. Sounds sketchy? It could be. Once I told you that the template method should not be overridden by the sub-classes. This is the one exception to the rule. You can override the template method by wrapping it in a decorator.

The next step is to implement the abstract method. Create a concrete Coat Decorator.

@RequiredArgsConstructor
public class CoatDecorator extends OuterwearDecorator {

private final Outfit outfit;

@Override
public void describeOuterwear() { log.info("camel coat");}
@Override
public void describeTop() { outfit.describeTop();}
@Override
public void describeBottom() { outfit.describeBottom();}
@Override
public void describeFootwear() { outfit.describeFootwear(); }
}

The decorator class behaves just like another class that implements the abstract methods. The only difference is, that it aggregates the base-class. It will allow stacking a few behaviors together.

Finally, add a new method to Outfit Service, that will create an autumn daily look with a coat for Tanja.

public void createAutumnOutfitWithCoat() {
Outfit autumnOutfit = seasonOutfitFactory.createOutfit(Season.AUTUMN);
autumnOutfit = new CoatDecorator(autumnOutfit);
autumnOutfit.createDailyLook();
}

The important part is that the basic outfit must be the first one in the stack. Next, wrap it in a Coat Decorator. Then call the createDailyLook() method, to Draw and Cut the described outfit. Your abstract decorator simply delegates the daily look creation to the Outfit object that it aggregates. Check the logs.

AutumnOutfit - white sweater
AutumnOutfit - ripped jeans
AutumnOutfit - veja sneakers
CoatDecorator - camel coat
Outfit - drawing outfit according to selections
Outfit - cutting drawn outfit

You may notice that daily look creation template steps were extended by coat decorator, without changing the base class. QED.

That’s all! Tanja has her paper clothes and I’m still thinking about valenki☃️.

This article was originally published by Gene zeiniss on medium.

Upvote


user
Created by

Gene Zeiniss

Java developer, backend guild master at a fintech startup, blogger (http://medium.com/@genezeiniss) 🤓


people
Post

Upvote

Downvote

Comment

Bookmark

Share


Related Articles