Шаблон Декоратор предназначен для динамического добавления к объекту новой функциональности. Он является гибкой альтернативой наследованию (в том числе множественному). Декоратор служит обёрткой для декорируемого объекта и реализует тот же интерфейс, что и класс декорируемого объекта. Однако декоратор добавляет свой код до, после или вместо вызовов методов декорируемого объекта. Это приводит к модификации исходного поведения и появлению новых возможностей.
Выделим следующих участников шаблона Декоратор (рис. 2). Интерфейс IComponent определяет общие функции исходных компонентов и декораторов[4]. Класс ConcreteComponent – это компонент, функциональность которого необходимо модифицировать. Класс Decorator – базовый декоратор (как правило, он включает механизм хранения компонента и реализует простую переадресацию). Конкретные декораторы ConcreteDecoratorA и ConcreteDecoratorB наследуются от базового декоратора, добавляя определённое состояние и (или) поведение.
Рис. 2. Схема шаблона Декоратор.
Разберём использование шаблона Декоратор на следующем примере. Пусть имеется класс Element, описывающий элемент блок-схемы. Для простоты ограничимся текстом элемента и методом его отображения на консоли.
|
|
public interface IElement
{
string Text { get; set; }
void Draw();
}
public class Element: IElement
{
public string Text { get; set; }
public void Draw()
{
Console.WriteLine("Element text = {0}", Text);
}
}
Создадим базовый декоратор для класса Element.
public class ElementDecorator: IElement
{
protected readonly IElement Component;
public ElementDecorator(IElement component)
{
Component = component;
}
public virtual string Text
{
get { return Component.Text; }
set { Component.Text = value; }
}
public virtual void Draw()
{
Component.Draw();
}
}
Теперь разработаем два декоратора: один для добавления отступов перед элементом, а второй – для обрамления элемента в скобки.
public class ElementWithIdent: ElementDecorator
{
public int Ident { get; set; }
public ElementWithIdent(IElement component): base(component)
{
}
public override void Draw()
{
MakeIdent();
base.Draw();
}
private void MakeIdent()
{
Console.Write(new string(' ', Ident));
}
}
public class ElementWithBrackets: ElementDecorator
{
public ElementWithBrackets(IElement component): base(component)
{
}
public override void Draw()
{
Console.WriteLine("[");
base.Draw();
Console.WriteLine("]");
}
}
Все готово к применению компонентов и их декораторов. Вначале создадим исходный компонент, а потом дополним его возможности, используя оба декоратора. Обратите внимание на то, что несколько декораторов могут независимо применяться к одному и тому же объекту, а также на то, что декоратор может декорировать объект, который уже декорирован.
// обыкновенный элемент
IElement element = new Element {Text = "Demo"};
element.Draw();
// декорирование отступом
IElement ei = new ElementWithIdent(element) {Ident = 4};
ei.Draw();
// дополнительное декорирование скобками
IElement eb = new ElementWithBrackets(ei);
eb.Draw();