- •А.А. Волосевич
- •3. Шаблоны и архитектура программ
- •3.1. Модульное тестирование
- •3.2. Шаблоны проектирования
- •3.3. Структурные шаблоны: Декоратор, Заместитель, мост Декоратор (Decorator)
- •Заместитель (Proxy)
- •Мост (Bridge)
- •3.4. Структурные шаблоны: компоновщик и приспособленец Компоновщик (Composite)
- •Приспособленец (Flyweight)
- •3.5. Структурные шаблоны: адаптер и фасад Адаптер (Adapter)
- •Фасад (Façade)
- •3.6. Порождающие шаблоны: прототип, фабричный метод, одиночка Прототип (Prototype)
- •Фабричный метод (Factory method)
- •Одиночка (Singleton)
- •3.7. Порождающие шаблоны: абстрактная фабрика и строитель Абстрактная фабрика (Abstract factory)
- •Строитель (Builder)
- •3.8. Шаблоны поведения: стратегия, состояние, шаблонный метод Стратегия (Strategy)
- •Состояние (State)
- •Шаблонный метод (Template method)
- •3.9. Шаблоны поведения: цепочка обязанностей и команда Цепочка обязанностей (Chain of responsibility)
- •Команда (Command)
- •3.10. Шаблоны поведения: итератор, посредник, наблюдатель Итератор (Iterator)
- •Посредник (Mediator)
- •Наблюдатель (Observer)
- •3.11. Шаблоны поведения: посетитель, интерпретатор, хранитель Посетитель (Visitor)
- •Интерпретатор (Interpreter)
- •Хранитель (Memento)
- •3.12. Некоторые неклассические шаблоны проектирования
- •Неизменный объект (Immutable object)
- •Пул объектов (Object pool)
- •Отложенная инициализация (Lazy initialization)
- •Нулевой объект (Null object)
- •3.13. Антипаттерны
- •3.14. Архитектура прогРаммного Обеспечения
- •«Клиент-сервер»
- •Архитектура, основанная на использовании компонентов
- •Многоуровневая архитектура
- •Шина сообщений
- •Выделенное представление
- •Объектно-ориентированная архитектура
- •Архитектура, ориентированная на сервисы
Команда (Command)
Шаблон Команда инкапсулирует команды в объекте таким образом, что можно управлять их выбором, ставить в очередь, отменять и выполнять иные манипуляции.
Классической иллюстрацией применения шаблона Команда является система меню любого оконного приложения. Пункты меню – это как раз и есть те команды, которые описывает шаблон. Некоторые команды в определенный момент времени доступны для выполнения, другие – нет. Заданный набор команд поддерживает функции отмены и повторного выполнения (Undo и Redo). Также обычно существует способ объединить несколько команд в одну макрокоманду.
Дизайн шаблона Команда показан на рис. 19.
Рис. 19. Дизайн шаблона Команда.
Объект Client выражает необходимость в определенных операциях в виде высокоуровневых терминов, зависящих от предметной области. Объекты Receiver знают, как выполнить требуемую операцию. Класс Command формирует интерфейс между Client и Receiver. В объекте-команде клиентские запросы ассоциируются с доступными операциями в объектах Receiver. Возможно, что клиент передает объектам Receiver некоторый контекст выполнения (или своё состояние).
При практической реализации шаблона Команда некоторые участники шаблона заменяются объектами-делегатами. Следующий пример кода – это реализация шаблона Команда для системы команд меню Paste и Print. При этом вводится логирование и поддержка отмены команд.
using System;
public delegate void Invoker();
public static class InvokerExtensions
{
private static int count;
public static int Count(this Invoker invoker)
{
return count;
}
public static void Log(this Invoker invoker)
{
count++;
}
}
public abstract class ICommand
{
public Invoker Execute, Redo, Undo;
}
public class CommandMenu
{
private class Paste : ICommand
{
public Paste(Document document)
{
Execute = delegate
{
Execute.Log();
document.Paste();
};
Redo = delegate
{
Redo.Log();
document.Paste();
};
Undo = delegate
{
Undo.Log();
document.Restore();
};
}
}
private class Print : ICommand
{
public Print(Document document)
{
Execute = delegate
{
Execute.Log();
document.Print();
};
Redo = delegate
{
Redo.Log();
document.Print();
};
Undo = delegate
{
Undo.Log();
Console.WriteLine("Cannot undo");
};
}
}
private static string clipboard;
private class Document
{
private readonly string name;
private string oldpage, page;
public Document(string name)
{
this.name = name;
}
public void Paste()
{
oldpage = page;
page += clipboard + "\n";
}
public void Restore()
{
page = oldpage;
}
public void Print()
{
Console.WriteLine("File " + name + " at " +
DateTime.Now + "\n" + page);
}
}
private static void Main()
{
var document = new Document("Greetings");
var paste = new Paste(document);
var print = new Print(document);
clipboard = "Hello, everyone";
paste.Execute();
print.Execute();
paste.Undo();
clipboard = "Bonjour, mes amis";
paste.Execute();
clipboard = "Guten morgen, meine Freunde";
paste.Redo();
print.Execute();
print.Undo();
Console.WriteLine("Logged " + paste.Execute.Count() +
" commands");
}
}