Computers

Design Patterns : Decorator pattern

Intent

  • Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub-classing for extending functionality. [GoF, p175]
  • Client-specified embellishment of a core object recursively wrapping it.

 

Diagram

 

Rules of thumb

  • Adapter provides a different interface to its subject. Proxy provides the same interface. but the decorator provides an enhanced interface. [Gof, p216]
  • Adopter changes an object’s interface, Decorator enhances an objects responsibilities, Decorator is thus more transparent to the client. As a consequence, decorator supports recursive composition, which isn’t possible with pure adapters. [GoF, p149]
  • Composite and decorator have similar structure diagrams, reflecting the fact that both rely on recursive composition to organize an open-ended number of objects [GoF, p219]
  • A decorator can be viewed as a degenerate composite with only one component. however, a decorator adds additional responsibilities – it isn’t intended for object aggregation. [GoF, p184]
  • Decorator is designed to let you add responsibilities to objects without sub-classing. Composite focus is not on embellishment but on representation. These intents are distinct but complementary. Consequently, composite and decorator are often used in concert. [GoF, p220]
  • Composite could use Chain of Responsibility to let components access global properties through their parent. It could also use Decorator to override these properties on parts of the composition. [GoF, p349]
  • Decorator and Proxy have different purposes but similar structures. Both describe how to provide a level of indirection to another object, and the implementations keep a reference to the object to which they forward requests. [GoF, p220]
  • Decorator lets you change the skin of an object. Strategy lets you change the guts. [GoF, p184]

 

Code Sample

using System;

using System.Collections.Generic;

namespace DoFactory.GangOfFour.Decorator.RealWorld

{

class MainApp {

static void Main() {

// 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>

abstract class LibraryItem {

private int _numCopies;

// Property

public int NumCopies

{

get { return _numCopies; }

set { _numCopies = value; }

}

public abstract void Display();

}

/// <summary>

/// The ‘ConcreteComponent’ class

/// </summary>

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>

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>

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>

class Borrowable : Decorator {

protected 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);

}

}

}

}

Share this post

Related Posts