Decorator – structural design pattern


Blog

It’s time to start a series of design patterns. The first will be decorator which is one of the structural design patterns.

But what are design patterns and when should we use them?  They are instructions or templates which can be used to resolve commonly occurring problems. They’re our programmer’s toolbox for everyday problems.

So this time look closer at decorator pattern, what problem it solves and how can we implement it.

Definition

The decorator pattern provides a way to add functionality to an object without modifying it and its interface. It’s an alternative to sub-classing and in some cases prevents from a combinatoric explosion.

To better understand this pattern let’s look at some use cases and code example.

Use cases

We use it when we want to extend an object with an additional feature, for example, we’ve got a window and want to add horizontal scroll to it. Or more technical: we want to compress file stream so what we can do is to wrap FileStream with GZipStream. Another use case can be the situation when we want to perform some action before some other action from our base object. For example, before drawing a window we want to log sth on the console or send some event. Look how it can be done in c#:

Example

This is our base class which implements IWindow interface with Draw method. We want to extend window with horizontal scroll and some logger logic.

public class Window : IWindow
{
    public string Draw()
    {
        return "Window";
    }
}

And this is the decorator which will add some functionality to our object without changing the interface.
So we’ve taken IWindow object in constructor and assign it to private field. Then in Draw method, we’ve run Draw method of our base object, added horizontal scroll to it, and in the end, returned modified object.

public class HorizontalScrollWindow : IWindow
{
	private readonly IWindow _window;

	public HorizontalScrollWindow(IWindow window)
	{
		_window = window;
	}

	public string Draw()
	{
		var window = _window.Draw();
		return AddHorizontalScroll(window);
	}

	private string AddHorizontalScroll(string window)
	{
		return window + " with horizontalscroll";
	}
}

Another example that I mention in use cases paragraph is performing some action before/after calling decorated object method. In this case, we log on the console some information and then draw the window.

public class WindowLogger : IWindow
{
	private readonly IWindow _window;

	public WindowLogger(IWindow window)
	{
		_window = window;
	}
	public string Draw()
	{
		ConsoleLogBeforeDraw();
		return _window.Draw();
	}

	private void ConsoleLogBeforeDraw()
	{
		Console.WriteLine("Log: Start drawing");
	}
}

Whole source code can be found on my github here: DECORATOR PATTERN

If You have any questions or want to share your use cases just leave comment below 🙂

Subscribe to my RSS feed!
follow us in feedly