In this blog post, i am going to discuss one of the an important design pattern in GOF patterns called “Decorator Design Pattern”. what is Decorator design pattern , how to use it in .NET loosely coupled software, it also represents the Open Closed Principal of (SOLID).
Definition: The pattern’s intent is to “Attach additional responsibilities to an object dynamically”.
Decorators also provides a flexible alternative to subclassing for extending functionality.
When and where you would use Decorator Design pattern:
The intent of the Decorator design pattern is to dynamically extend an object’s behavior. This ability to dynamically attach new behavior to objects is done by a Decorator class that ‘wraps itself’ around the original class.
The Decorator pattern combines polymorphism with delegation. It is polymorphic with the original class so that clients can invoke it just like the original class. In most cases, method calls are delegated to the original class and then the results are acted upon, or decorated, with additional functionality. Decoration is a flexible technique because if takes place at runtime, as opposed to inheritance which takes place at compile time.
Here is the general structure of the Decorator design pattern.
Figure 1.0
Let’s say, for instance, that you’ve an Abstraction called IGreeter that contains
a Greet method. This is shown in this code snippet:
public interface IGreeter { string Greet(string name); }
For this Abstraction, you can create a simple implementation that creates a formal greeting:
public class FormalGreeter : IGreeter { public string Greet(string name) { return "Hello," + name + "."; } }
Now let’s create a Decorator class, which modify the input it received before delegating the call.
Create a TitledGreeterDecorator class as below
public class TitledGreeterDecorator : IGreeter { private readonly IGreeter decoratee; public TitledGreeterDecorator(IGreeter decoratee) { this.decoratee = decoratee; } // Greet method add new text and delegate the call to original class public string Greet(string name) { string titledName = "Mr. " + name; return this.decoratee.Greet(titledName); } }
Now create another class as “NiceToMeetYouGreeterDecorator”, this decorator may decided to modify the return value.
public class NiceToMeetYouGreeterDecorator : IGreeter { private readonly IGreeter decoratee; public NiceToMeetYouGreeterDecorator(IGreeter decoratee) { this.decoratee = decoratee; } public string Greet(string name) { string greet = this.decoratee.Greet(name); return greet + " Nice to meet you."; } }
Given the two previous examples, you can wrap the latter around the former to
compose a combination that modifies both input and output:
IGreeter greeter = new NiceToMeetYouGreeterDecorator( new TitledGreeterDecorator( new FormalGreeter())); string greet = greeter.Greet("Michael . Jackson"); Console.WriteLine(greet);
This produces the following output:
Hello, Mr. Michael . Jackson. Nice to meet you.
Decorator in the .NET Framework
Examples of the Decorator in the .NET Framework include a set of classes that are designed around the Stream class. The Stream class is an abstract class that reads or writes a sequence of bytes from an IO device (disk, sockets, memory, etc.). The BufferedStream class is a Decorator that wraps the Stream class and reads and writes large chunks of bytes for better performance. Similarly, the CryptoStream class wraps a Stream and encrypts and decrypts a stream of bytes on the fly.
Both BufferedStream and CryptoStream expose the same interface as Stream with methods such as Read, Write, Seek, Flush and others. Clients won’t know the difference with the original Stream. Decorator classes usually have a constructor with an argument that represents the class they intent to decorate: for example:
new BufferedStream (Stream stream).