0% found this document useful (0 votes)
44 views

Decorator Pattern: Closed For Modification But Open For Extension

The Decorator pattern allows adding new behaviors to individual objects dynamically at runtime without affecting other objects. It works by having decorator classes that contain and inherit from the class being decorated, allowing decorators to add or override behaviors while maintaining a common interface. Some examples of its use include adding borders or tags to photos, compressing video streams, and creating mobile-friendly displays.
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
44 views

Decorator Pattern: Closed For Modification But Open For Extension

The Decorator pattern allows adding new behaviors to individual objects dynamically at runtime without affecting other objects. It works by having decorator classes that contain and inherit from the class being decorated, allowing decorators to add or override behaviors while maintaining a common interface. Some examples of its use include adding borders or tags to photos, compressing video streams, and creating mobile-friendly displays.
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 6

6/12/2012

Decorator Pattern
One of the most important aspects of the development process that developers and programmers have to grapple with is change, which is why design patterns were introduced in the first place. In particular, design patterns are intended to help you handle change as you have to adapt your code to new and unforeseen circumstances. Developers spend much more time extending and changing code than they do originally developing it

Design Pattern

Closed for modification but open for extension


The Decorator pattern allows you to write your code and avoid modification, while still extending that code if needed. As much as possible, make your code closed for modification, but open for extension. In other words, design your core code so that it doesnt have to be modified a lot, but may be extended as needed.

Role
The role of the Decorator pattern is to provide a way of attaching new state and behavior to an object dynamically. The object does not know it is being decorated, which makes this a useful pattern for evolving systems. A key implementation point in the Decorator pattern is that decorators both inherit the original class and contain an instantiation of it.

Illustration
As its name suggests, the Decorator pattern takes an existing object and adds to it. As an example, consider a photo that is displayed on a screen. There are many ways to add to the photo, such as putting a border around it or specifying tags related to thecontent. Such additions can be displayed on top of the photo, as shown in Figure.

6/12/2012

The combination of the original photo and some new content forms a new object. In the second image shown , there are four objects:
the original photo as shown to the left, the object that provides a border, and two tag objects with different data associated with them. Each of them is a Decorator object. Given that the number of ways of decorating photos is endless, we can have many such new objects.

The beauty of this pattern is that


The original object is unaware of any decorations. There is no one big feature-laden class with all the options in it. The decorations are independent of each other. The decorations can be composed together in a mix-and-match fashion.

Design
Now, we can specify the players in the Decorator pattern in a UML diagram. The essential players in this UML diagram are: Component - An original class of objects that can have operations added or modified (there may be more than one such class) Operation - An operation in IComponent objects that can be replaced (there may be several operations) Icomponent - The interface that identifies the classes of objects that can be decorated (Component is one of these) Decorator - A class that conforms to the IComponent interface and adds state and/or behavior (there may be more than one such class)

Decorator Pattern Class Diagram


The center of the UML diagram is the Decorator class. It includes two types of relationships with the IComponent interface: Is-a - The is-a relationship is shown by a dotted arrow from the Decorator to IComponent, indicating that Decorator realizes the IComponent interface. The fact that Decorator inherits from IComponent means that Decorator objects can be used wherever IComponent objects are expected. The Component class is also in an is-a relationship with IComponent, and therefore the client can use Component and Decorator objects interchangeablythe heart of the Decorator pattern. Has-a

6/12/2012

Has-a - The has-a relationship is shown by an open diamond on the Decorator, linked to IComponent. This indicates that the Decorator instantiates one or more IComponent objects and that decorated objects can outlive the originals. The Decorator uses the component attribute (of type IComponent) to invoke any replacement Operation it might wish to override. This is the way the Decorator pattern achieves its objective.

The addedBehavior operation and the addedState attribute in the Decorator class are other optional ways of extending what is in the original Component objects.

From this list, we can see that the following would be valid statements in a Client wanting to put two tags on a photo: Photo photo = new Photo( ); Tag foodTag = new Tag (photo, "Food",1); Tag colorTag = new Tag (foodTag, "Yellow",2);

By the is-a relationship, photo, foodTag, and colorTag are all IComponent objects. Each of the tags (the decorators) is created with a Component, which might be a photo or an already tagged photo.

Multiple Guises
Multiple components Different components that conform to the interface can also be decorated. For example, we could have a class that draws people, houses, ships, and so on from simple shapes and lines. They too could be tagged. It is for this reason that the IComponent interface is important, even if it does not contain any operations. In the case where we are sure there will only ever be one class of components, we can dispense with the IComponent interface and have the decorators directly inherit from Component.

Multiple Guises
Multiple decorators We have seen that we can create different instances of a Tag decorator. We can also consider having other types of decorators, such as Border decorators or even decorators that make the photo invisible. No matter what the decorators are, each contains a component object, which might itself be a decorator, setting off a chain of changes

6/12/2012

Multiple Guises
Multiple operations Our illustration focuses on drawing as the chief operation for photos and decorations. Other examples will lend themselves to many more optional operations. Some of these will be part of the original component and its interface, whereas some will be added behaviors in certain decorators only. The client can call any of the operations individually on any of the components (decorated or otherwise) to which it has access.

Implementation
The Decorator patterns key feature: It does not rely on inheritance for extending behavior. If the Tag class had to inherit from the Photo class to add one or two methods, Tags would carry everything concerned with Photos around with them,making them very heavyweight objects. Instead, having the Tag class implement a Photo interface and then add behavior keeps the Tag objects lean. They can:
Implement any methods in the interface, changing the initial behavior of the component Add any new state and behavior Access any public members via the object passed at construction

Decorator pattern theory code


using System; class DecoratorPattern { // Decorator Pattern Judith Bishop Dec 2006 // Shows two decorators and the output of various // combinations of the decorators on the basic component interface IComponent { string Operation( ); } class Component : Icomponent {
public string Operation ( ) { return "I am walking "; }

class DecoratorA : IComponent { IComponent component; public DecoratorA (IComponent c) { component = c; } public string Operation( ) { string s = component.Operation( ); s += "and listening to Classic FM "; return s; } }

class DecoratorB : IComponent { IComponent component; public string addedState = "past the Coffee Shop "; public DecoratorB (IComponent c) { component = c; } public string Operation ( ) { string s = component.Operation ( ); s += "to school "; return s; } public string AddedBehavior( ) { return "and I bought a cappuccino "; } }

class Client { static void Display(string s, IComponent c) { Console.WriteLine(s+ c.Operation( )); } } static void Main( ) { Console.WriteLine("Decorator Pattern\n"); IComponent component = new Component( ); Console.Writeline("1. Basic component: ", component); Console.Writeline("2. A-decorated : ", new DecoratorA(component)); Console.Writeline("3. B-decorated : ", new DecoratorB(component)); Console.Writeline("4. B-A-decorated : ", new DecoratorB(new DecoratorA(component))); // Explicit DecoratorB DecoratorB b = new DecoratorB(new Component( )); Display("5. A-B-decorated : ", new DecoratorA(b)); // Invoking its added state and added behavior Console.WriteLine("\t\t\t"+b.addedState + b.AddedBehavior( )); }

6/12/2012

Use
/* Output Decorator Pattern 1. Basic component: I am walking 2. A-decorated : I am walking and listening to Classic FM 3. B-decorated : I am walking to school 4. B-A-decorated : I am walking and listening to Classic FM to school 5. A-B-decorated : I am walking to school and listening to Classic FM past the Coffee Shop and I bought a cappuccino

Here are four ways the Decorator pattern is used in the real world:
As our small example illustrated, the Decorator pattern fits well in the graphics world. It is equally at home with video and sound; for instance, video streaming can be compressed at different rates, and sound can be input to a simultaneous translation service.

Use
At a more mundane level, decorators abound in the I/O APIs of C#. Consider the following hierarchy:
System.IO.Stream System.IO.BufferedStream System.IO.FileStream System.IO.MemoryStream System.Net.Sockets.NetworkStream System.Security.Cryptography.CryptoStream

Use
In todays world of mobile devices, web browsers and other mobile applications thrive on the Decorator pattern. They can create display objects suitable for smaller screens that include scroll bars and exclude banners that would be standard on desktop display browsers, for example.

The subclasses decorate Stream because they inherit from it, and they also contain an instance of a Stream that is set up when an object is constructed. Many of their properties and methods relate to this instance

Use
The Decorator pattern is so useful that there are now actual Decorator classes in .NET 3.0. The one in System.Windows.Controls provides a base class for elements that apply effects onto or around a single child element, such as Border or Viewbox.

Use the Decorator pattern when


You have:
An existing component class that may be unavailable for subclassing.

You want to:


Attach additional state or behavior to an object dynamically. Make changes to some objects in a class without affecting others. Avoid subclassing because too many classes could result.

6/12/2012

You might also like