Definition
|
Attach additional responsibilities to an object dynamically. decorators provide a flexible alternative to subclassing for extending functionality. |
UML class digoal
Participant
|
The classes and/or objects participating in the decorator pattern are:
- Component(Libraryitem)
- Defines the interface for objects that can have responsibilities added to them dynamically.
- Concretecomponent(Book, video)
- Defines an object to which additional responsibilities can be attached.
- Decorator(Decorator)
- Maintains a reference to a component object and defines an interface that conforms to component's interface.
- Concretedecorator(Borrowable)
- Adds responsibilities to the component.
|
Sample Code in C #
This structural code demonstrates the decorator pattern which dynamically adds extra functionality to an existing object.
// Decorator pattern -- Structural example |
using System;
// "Component"
abstract class Component
{
// Methods
abstract public void Operation();
}
// "ConcreteComponent"
class ConcreteComponent : Component
{
// Methods
override public void Operation()
{
Console.WriteLine("ConcreteComponent.Operation()");
}
}
// "Decorator"
abstract class Decorator : Component
{
// Fields
protected Component component;
// Methods
public void SetComponent( Component component )
{
this.component = component;
}
override public void Operation()
{
if( component != null )
component.Operation();
}
}
// "ConcreteDecoratorA"
class ConcreteDecoratorA : Decorator
{
// Fields
private string addedState;
// Methods
override public void Operation()
{
base.Operation();
addedState = "new state";
Console.WriteLine("ConcreteDecoratorA.Operation()");
}
}
// "ConcreteDecoratorB"
class ConcreteDecoratorB : Decorator
{
// Methods
override public void Operation()
{
base.Operation();
AddedBehavior();
Console.WriteLine("ConcreteDecoratorB.Operation()");
}
void AddedBehavior()
{
}
}
/// <summary>
/// Client test
/// </summary>
public class Client
{
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();
}
} |
This real-world code demonstrates the decorator pattern in which 'borrowable' functionality is added to existing library items (books and videos ).
// Decorator pattern -- Real World example |
using System;
using System.Collections;
// "Component"
abstract class LibraryItem
{
// Fields
private int numCopies;
// Properties
public int NumCopies
{
get{ return numCopies; }
set{ numCopies = value; }
}
// Methods
public abstract void Display();
}
// "ConcreteComponent"
class Book : LibraryItem
{
// Fields
private string author;
private string title;
// Constructors
public Book(string author,string title,int numCopies)
{
this.author = author;
this.title = title;
this.NumCopies = numCopies;
}
// Methods
public override void Display()
{
Console.WriteLine( "\nBook ------ " );
Console.WriteLine( " Author: {0}", author );
Console.WriteLine( " Title: {0}", title );
Console.WriteLine( " # Copies: {0}", NumCopies );
}
}
// "ConcreteComponent"
class Video : LibraryItem
{
// Fields
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;
}
// Methods
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}", playTime );
}
}
// "Decorator"
abstract class Decorator : LibraryItem
{
// Fields
protected LibraryItem libraryItem;
// Constructors
public Decorator ( LibraryItem libraryItem )
{
this.libraryItem = libraryItem;
}
// Methods
public override void Display()
{
libraryItem.Display();
}
}
// "ConcreteDecorator"
class Borrowable : Decorator
{
// Fields
protected ArrayList borrowers = new ArrayList();
// Constructors
public Borrowable( LibraryItem libraryItem )
: base( libraryItem ) {}
// Methods
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: {0}", borrower );
}
}
/// <summary>
/// DecoratorApp test
/// </summary>
public class DecoratorApp
{
public static void Main( string[] args )
{ // Create book and video and display
Book book = new Book( "Schnell", "My Home", 10 );
Video video = new Video( "Spielberg",
"Schindler's list", 23, 60 );
book.Display();
video.Display();
// Make video borrowable, then borrow and display
Console.WriteLine( "\nVideo made borrowable:" );
Borrowable borrowvideo = new Borrowable( video );
borrowvideo.BorrowItem( "Cindy Lopez" );
borrowvideo.BorrowItem( "Samuel King" );
borrowvideo.Display();
}
} |