Декоратор (Decorator)
Также известен как Обертка (Wrapper).
Паттерн Декоратор динамически наделяет объект новыми возможностями и является гибкой альтернативой субклассированию в области расширения функциональности.
-
Component - абстрактный компонент
-
ConcreteComponent - конкретный компонент
-
Decorator - абстрактный декоратор
-
ConcreteDecorator - конкретный декоратор
Абстрактная реализация на C# (GoF)
/// <summary>
/// MainApp startup class for Structural
/// Decorator Design Pattern.
/// </summary>
internal class MainApp
{
/// <summary>
/// Entry point into console application.
/// </summary>
private static void Main()
{
// 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>
internal abstract class Component
{
public abstract void Operation();
}
/// <summary>
/// The 'ConcreteComponent' class
/// </summary>
internal class ConcreteComponent : Component
{
public override void Operation()
{
Console.WriteLine("ConcreteComponent.Operation()");
}
}
/// <summary>
/// The 'Decorator' abstract class
/// </summary>
internal 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>
internal class ConcreteDecoratorA : Decorator
{
public override void Operation()
{
base.Operation();
Console.WriteLine("ConcreteDecoratorA.Operation()");
}
}
/// <summary>
/// The 'ConcreteDecoratorB' class
/// </summary>
internal class ConcreteDecoratorB : Decorator
{
public override void Operation()
{
base.Operation();
AddedBehavior();
Console.WriteLine("ConcreteDecoratorB.Operation()");
}
private void AddedBehavior()
{
}
}
Реальная реализация на C# (GoF)
/// <summary>
/// MainApp startup class for Real-World
/// Decorator Design Pattern.
/// </summary>
internal class MainApp
{
/// <summary>
/// Entry point into console application.
/// </summary>
private 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>
internal 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>
internal 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>
internal 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>
internal 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>
internal 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);
}
}
}
Улучшенная реальная реализация на C# (GoF)
/// <summary>
/// MainApp startup class for .NET optimized
/// Decorator Design Pattern.
/// </summary>
internal class MainApp
{
/// <summary>
/// Entry point into console application.
/// </summary>
private static void Main()
{
// Create book
var book = new Book("Worley", "Inside ASP.NET", 10);
book.Display();
// Create video
var video = new Video("Spielberg", "Jaws", 23, 92);
video.Display();
// Make video borrowable, then borrow and display
Console.WriteLine("\nMaking video borrowable:");
var borrow = new Borrowable<Video>(video);
borrow.BorrowItem("Customer #1");
borrow.BorrowItem("Customer #2");
borrow.Display();
// Wait for user
Console.ReadKey();
}
}
/// <summary>
/// The 'Component' abstract class
/// </summary>
internal abstract class LibraryItem<T>
{
// Each T has its own NumCopies
public static int NumCopies { get; set; }
public abstract void Display();
}
/// <summary>
/// The 'ConcreteComponent' class
/// </summary>
internal class Book : LibraryItem<Book>
{
private string author;
private string title;
// Constructor
public Book(string author, string title, int numCopies)
{
this.author = author;
this.title = title;
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>
internal class Video : LibraryItem<Video>
{
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;
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>
internal abstract class Decorator<T> : LibraryItem<T>
{
private LibraryItem<T> libraryItem;
// Constructor
public Decorator(LibraryItem<T> libraryItem)
{
this.libraryItem = libraryItem;
}
public override void Display()
{
libraryItem.Display();
}
}
/// <summary>
/// The 'ConcreteDecorator' class
/// </summary>
internal class Borrowable<T> : Decorator<T>
{
private List<string> borrowers = new List<string>();
// Constructor
public Borrowable(LibraryItem<T> libraryItem)
: base(libraryItem)
{
}
public void BorrowItem(string name)
{
borrowers.Add(name);
NumCopies--;
}
public void ReturnItem(string name)
{
borrowers.Remove(name);
NumCopies++;
}
public override void Display()
{
base.Display();
borrowers.ForEach(b => Console.WriteLine(" borrower: " + b));
}
}
Реализация на C# (Head First)
internal class StarbuzzCoffee
{
private static void Main(string[] args)
{
Beverage beverage = new Espresso();
Console.WriteLine(beverage.Description
+ " $" + beverage.Cost);
Beverage beverage2 = new DarkRoast();
beverage2 = new Mocha(beverage2);
beverage2 = new Mocha(beverage2);
beverage2 = new Whip(beverage2);
Console.WriteLine(beverage2.Description
+ " $" + beverage2.Cost);
Beverage beverage3 = new HouseBlend();
beverage3 = new Soy(beverage3);
beverage3 = new Mocha(beverage3);
beverage3 = new Whip(beverage3);
Console.WriteLine(beverage3.Description
+ " $" + beverage3.Cost);
// Wait for user
Console.ReadKey();
}
}
#region Beverage
public class Beverage
{
public virtual string Description { get; protected set; }
public virtual double Cost { get; protected set; }
}
public class DarkRoast : Beverage
{
public DarkRoast()
{
Description = "Dark Roast Coffee";
Cost = 0.99;
}
}
public class Decaf : Beverage
{
public Decaf()
{
Description = "Decaf Coffee";
Cost = 1.05;
}
}
public class Espresso : Beverage
{
public Espresso()
{
Description = "Espresso";
Cost = 1.99;
}
}
public class HouseBlend : Beverage
{
public HouseBlend()
{
Description = "House Blend Coffee";
Cost = 0.89;
}
}
#endregion Beverage
#region CondimentDecorator
public abstract class CondimentDecorator : Beverage
{
}
public class Whip : CondimentDecorator
{
private Beverage _beverage;
public Whip(Beverage beverage)
{
this._beverage = beverage;
}
public override string Description
{
get { return _beverage.Description + ", Whip"; }
}
public override double Cost
{
get { return .10 + _beverage.Cost; }
}
}
public class Milk : CondimentDecorator
{
private Beverage _beverage;
public Milk(Beverage beverage)
{
this._beverage = beverage;
}
public override string Description
{
get { return _beverage.Description + ", Milk"; }
}
public override double Cost
{
get { return .10 + _beverage.Cost; }
}
}
public class Mocha : CondimentDecorator
{
private Beverage _beverage;
public Mocha(Beverage beverage)
{
this._beverage = beverage;
}
public override string Description
{
get { return _beverage.Description + ", Mocha"; }
}
public override double Cost
{
get { return .20 + _beverage.Cost; }
}
}
public class Soy : CondimentDecorator
{
private Beverage _beverage;
public Soy(Beverage beverage)
{
this._beverage = beverage;
}
public override string Description
{
get { return _beverage.Description + ", Soy"; }
}
public override double Cost
{
get { return .15 + _beverage.Cost; }
}
}
#endregion CondimentDecorator
Реализация на JAVA
TODO