The Decorator design pattern attaches additional responsibilities to an object dynamically. This pattern provide a flexible alternative to subclassing for extending functionality.
A visualization of the classes and objects participating in this pattern.
The classes and objects participating in this pattern include:
LibraryItem
)
Book, Video
)
Decorator
)
Borrowable
)
This structural code demonstrates the Decorator pattern which dynamically adds extra functionality to an existing object.
using System;
namespace Decorator.Structural
{
/// <summary>
/// Decorator Design Pattern
/// </summary>
public class Program
{
public static void Main(string[] args)
{
// Create ConcreteComponent and two Decorators
ConcreteComponent c = new ConcreteComponent();
ConcreteDecoratorA d1 = new ConcreteDecoratorA();
ConcreteDecoratorB d2 = new ConcreteDecoratorB();
// Link decorators
d1.SetComponent(c);
d2.SetComponent(d1);
d2.Operation();
// Wait for user
Console.ReadKey();
}
}
/// <summary>
/// The 'Component' abstract class
/// </summary>
public abstract class Component
{
public abstract void Operation();
}
/// <summary>
/// The 'ConcreteComponent' class
/// </summary>
public class ConcreteComponent : Component
{
public override void Operation()
{
Console.WriteLine("ConcreteComponent.Operation()");
}
}
/// <summary>
/// The 'Decorator' abstract class
/// </summary>
public abstract class Decorator : Component
{
protected Component component;
public void SetComponent(Component component)
{
this.component = component;
}
public override void Operation()
{
if (component != null)
{
component.Operation();
}
}
}
/// <summary>
/// The 'ConcreteDecoratorA' class
/// </summary>
public class ConcreteDecoratorA : Decorator
{
public override void Operation()
{
base.Operation();
Console.WriteLine("ConcreteDecoratorA.Operation()");
}
}
/// <summary>
/// The 'ConcreteDecoratorB' class
/// </summary>
public class ConcreteDecoratorB : Decorator
{
public override void Operation()
{
base.Operation();
AddedBehavior();
Console.WriteLine("ConcreteDecoratorB.Operation()");
}
void AddedBehavior()
{
}
}
}
This real-world code demonstrates the Decorator pattern in which 'borrowable' functionality is added to existing library items (books and videos).
using System;
using System.Collections.Generic;
namespace Decorator.RealWorld
{
/// <summary>
/// Decorator Design Pattern
/// </summary>
public class Program
{
public static void Main(string[] args)
{
// Create book
Book book = new Book("Worley", "Inside ASP.NET", 10);
book.Display();
// Create video
Video video = new Video("Spielberg", "Jaws", 23, 92);
video.Display();
// Make video borrowable, then borrow and display
Console.WriteLine("\nMaking video borrowable:");
Borrowable borrowvideo = new Borrowable(video);
borrowvideo.BorrowItem("Customer #1");
borrowvideo.BorrowItem("Customer #2");
borrowvideo.Display();
// Wait for user
Console.ReadKey();
}
}
/// <summary>
/// The 'Component' abstract class
/// </summary>
public abstract class LibraryItem
{
private int numCopies;
public int NumCopies
{
get { return numCopies; }
set { numCopies = value; }
}
public abstract void Display();
}
/// <summary>
/// The 'ConcreteComponent' class
/// </summary>
public class Book : LibraryItem
{
private string author;
private string title;
// Constructor
public Book(string author, string title, int numCopies)
{
this.author = author;
this.title = title;
this.NumCopies = numCopies;
}
public override void Display()
{
Console.WriteLine("\nBook ------ ");
Console.WriteLine(" Author: {0}", author);
Console.WriteLine(" Title: {0}", title);
Console.WriteLine(" # Copies: {0}", NumCopies);
}
}
/// <summary>
/// The 'ConcreteComponent' class
/// </summary>
public class Video : LibraryItem
{
private string director;
private string title;
private int playTime;
// Constructor
public Video(string director, string title, int numCopies, int playTime)
{
this.director = director;
this.title = title;
this.NumCopies = numCopies;
this.playTime = playTime;
}
public override void Display()
{
Console.WriteLine("\nVideo ----- ");
Console.WriteLine(" Director: {0}", director);
Console.WriteLine(" Title: {0}", title);
Console.WriteLine(" # Copies: {0}", NumCopies);
Console.WriteLine(" Playtime: {0}\n", playTime);
}
}
/// <summary>
/// The 'Decorator' abstract class
/// </summary>
public abstract class Decorator : LibraryItem
{
protected LibraryItem libraryItem;
// Constructor
public Decorator(LibraryItem libraryItem)
{
this.libraryItem = libraryItem;
}
public override void Display()
{
libraryItem.Display();
}
}
/// <summary>
/// The 'ConcreteDecorator' class
/// </summary>
public class Borrowable : Decorator
{
protected readonly List<string> borrowers = new List<string>();
// Constructor
public Borrowable(LibraryItem libraryItem)
: base(libraryItem)
{
}
public void BorrowItem(string name)
{
borrowers.Add(name);
libraryItem.NumCopies--;
}
public void ReturnItem(string name)
{
borrowers.Remove(name);
libraryItem.NumCopies++;
}
public override void Display()
{
base.Display();
foreach (string borrower in borrowers)
{
Console.WriteLine(" borrower: " + borrower);
}
}
}
}
The .NET optimized code demonstrates the
same real-world situation as above but uses modern, built-in .NET features,
such as, generics, reflection, LINQ, lambda functions, etc.
You can find an example on our Singleton pattern page.
All other patterns (and much more) are available in our Dofactory .NET product.
Not only does Dofactory .NET cover the Gang of Four and Enterprise patterns, it also includes
pattern architectures, low-code, and RAD (Rapid Application Development) techniques.
Accelerate development to where you can write
entire solutions in just 33 days!.
This unique package will change your developer lifestyle.
Here's what is included: