Создать интерпретатор, который решает данную задачу. Например, задача поиска строк по образцу может быть решена посредством создания интерпретатора, определяющего грамматику языка. "Клиент" строит предложение в виде абстрактного синтаксического дерева, в узлах которого находятся объекты классов "НетерминальноеВыражение" и "ТерминальноеВыражение" (рекурсивное), затем "Клиент" инициализирует контекст и вызывает операцию Разобрать(Контекст). На каждом узле типа "НетерминальноеВыражение" определяется операция Разобрать для каждого подвыражения. Для класса "ТерминальноеВыражение" операция Разобрать определяет базу рекурсии. "АбстрактноеВыражение" определяет абстрактную операцию Разобрать, общую для всех узлов в абстрактном синтаксическом дереве. "Контекст" содержит информацию, глобальную по отношению к интерпретатору.
namespace Interpreter_DesignPattern { using System; using System.Collections; class Context { } abstract class AbstractExpression { abstract public void Interpret(Context c); } // Класс, представляющий терминальный символ class TerminalExpression: AbstractExpression { override public void Interpret(Context c) { } } // Класс, представляющий грамматическое правило class NonterminalExpression: AbstractExpression { override public void Interpret(Context c) { } } public class Client { public static int Main(string[] args) { Context c = new Context(); ArrayList l = new ArrayList(); // На самом деле здесь должно быть дерево l.Add(new TerminalExpression()); l.Add(new NonterminalExpression()); // interpret foreach (AbstractExpression exp in l) { exp.Interpret(c); } return 0; } } }Шаблон Mediator(также известный как Посредник) Обеспечить взаимодействие множества объектов, сформировав при этом слабую связанность и избавив объекты от необходимости явно ссылаться друг на друга.
namespace Mediator_DesignPattern { using System; class Mediator { private DataProviderColleague dataProvider; private DataConsumerColleague dataConsumer; public void IntroduceColleagues(DataProviderColleague c1, DataConsumerColleague c2) { dataProvider = c1; dataConsumer = c2; } public void DataChanged() { int i = dataProvider.MyData; dataConsumer.NewValue(i); } } class DataConsumerColleague { public void NewValue(int i) { Console.WriteLine("New value {0}", i); } } class DataProviderColleague { private Mediator mediator; private int iMyData=0; public int MyData { get { return iMyData; } set { iMyData = value; } } public DataProviderColleague(Mediator m) { mediator = m; } public void ChangeData() { iMyData = 403; if (mediator!= null) mediator.DataChanged(); } } public class Client { public static int Main(string[] args) { Mediator m = new Mediator(); DataProviderColleague c1 = new DataProviderColleague(m); DataConsumerColleague c2 = new DataConsumerColleague(); m.IntroduceColleagues(c1,c2); c1.ChangeData(); return 0; } } }4.4 Наблюдатель, Observer — поведенческий шаблон проектирования. Также известен как «подчинённые» (Dependents), «издатель-подписчик» (Publisher-Subscriber).
Определяет зависимость типа «один ко многим» между объектами таким образом, что при изменении состояния одного объекта все зависящие от него оповещаются об этом событии.
Шаблон «наблюдатель» применяется в тех случаях, когда система обладает следующими свойствами:
- существует, как минимум, один объект, рассылающий сообщения
- имеется не менее одного получателя сообщений, причём их количество и состав могут изменяться во время работы приложения.
Данный шаблон часто применяют в ситуациях, в которых отправителя сообщений не интересует, что делают с предоставленной им информацией получатели.
namespace Observer_DesignPattern { using System; using System.Collections; class Subject { private ArrayList list = new ArrayList(); private string strImportantSubjectData = "Initial"; public string ImportantSubjectData { get { return strImportantSubjectData; } set { strImportantSubjectData = value; } } public void Attach(Observer o) { list.Add(o); o.ObservedSubject = this; } public void Detach(Observer o) { } public void Notify() { foreach (Observer o in list) { o.Update(); } } } class ConcreteSubject: Subject { public void GetState() { } public void SetState() { } } abstract class Observer { protected Subject s; public Subject ObservedSubject { get { return s; } set { s = value; } } abstract public void Update(); } class ConcreteObserver: Observer { private string observerName; public ConcreteObserver(string name) { observerName = name; } override public void Update() { Console.WriteLine("In Observer {0}: data from subject = {1}", observerName, s.ImportantSubjectData); } } public class Client { public static int Main(string[] args) { ConcreteSubject s = new ConcreteSubject(); ConcreteObserver o1 = new ConcreteObserver("first observer"); ConcreteObserver o2 = new ConcreteObserver("second observer"); s.Attach(o1); s.Attach(o2); s. ImportantSubjectData = "This is important subject data"; s.Notify(); return 0; } } }4.5 Состояние (State) — шаблон проектирования. Используется в тех случаях, когда во время выполнения программы объект должен менять свое поведение в зависимости от своего состояния т.е “на лету”
4.6
Стратегия, Strategy — поведенческий шаблон проектирования, предназначенный для определения семейства алгоритмов, инкапсуляции каждого из них и обеспечения их взаимозаменяемости. Это позволяет выбирать алгоритм путем определения соответствующего класса. Шаблон Strategy позволяет менять выбранный алгоритм независимо от объектов-клиентов, которые его используют.
Задача
Выбор алгоритма, который следует применить, в зависимости от типа выдавшего запрос клиента или обрабатываемых данных. Если используется правило, которое не подвержено изменениям, нет необходимости обращаться к шаблону «стратегия».
- Программа должна обеспечивать различные варианты алгоритма или поведения
- Нужно изменять поведение каждого экземпляра класса
- Необходимо изменять поведение объектов на стадии выполнения
- Введение интерфейса позволяет классам-клиентам ничего не знать о классах, реализующих этот интерфейс и инкапсулирующих в себе конкретные алгоритмы
Реализация заключается в отделение процедуры выбора алгоритма от его реализации. Это позволяет сделать выбор на основании контекста.
Пример 1
using System; namespace DesignPatterns.Behavioral.Strategy{ /// <summary> /// Интерфейс «Стратегия» определяет функциональность (в данном примере это метод /// <see cref="Algorithm">Algorithm</see>), которая должна быть реализована /// конкретными классами стратегий. Другими словами, метод интерфейса определяет /// решение некой задачи, а его реализации в конкретных классах стратегий определяют, /// КАК, КАКИМ ПУТЁМ эта задача будет решена. /// </summary> public interface IStrategy { void Algorithm(); } /// <summary> /// Первая конкретная реализация-стратегия. /// </summary> public class ConcreteStrategy1: IStrategy { public void Algorithm() { Console.WriteLine("Выполняется алгоритм стратегии 1."); } } /// <summary> /// Вторая конкретная реализация-стратегия. /// Реализаций может быть сколько угодно много. /// </summary> public class ConcreteStrategy2: IStrategy { public void Algorithm() { Console.WriteLine("Выполняется алгоритм стратегии 2."); } } /// <summary> /// Контекст, использующий стратегию для решения своей задачи. /// </summary> public class Context { /// <summary> /// Ссылка на интерфейс <see cref="IStrategy">IStrategy</see> /// позволяет автоматически переключаться между конкретными реализациями /// (другими словами, это выбор конкретной стратегии). /// </summary> private IStrategy _strategy; /// <summary> /// Конструктор контекста. /// Инициализирует объект стратегией. /// </summary> /// <param name="strategy"> /// Стратегия. /// </param> public Context(IStrategy strategy) { _strategy = strategy; } /// <summary> /// Метод для установки стратегии. /// Служит для смены стратегии во время выполнения. /// В C# может быть реализован также как свойство записи. /// </summary> /// <param name="strategy"> /// Новая стратегия. /// </param> public void SetStrategy(IStrategy strategy) { _strategy = strategy; } /// <summary> /// Некоторая функциональность контекста, которая выбирает /// стратегию и использует её для решения своей задачи. /// </summary> public void ExecuteOperation() { _strategy.Algorithm(); } } /// <summary> /// Класс приложения. /// В данном примере выступает как клиент контекста. /// </summary> public static class Program { /// <summary> /// Точка входа в программу. /// </summary> public static void Main() { // Создём контекст и инициализируем его первой стратегией. Context context = new Context(new ConcreteStrategy1()); // Выполняем операцию контекста, которая использует первую стратегию. context.ExecuteOperation(); // Заменяем в контексте первую стратегию второй. context.SetStrategy(new ConcreteStrategy2()); // Выполняем операцию контекста, которая теперь использует вторую стратегию. context.ExecuteOperation(); } }}Пример 2
namespace Strategy_DesignPattern { using System; abstract class Strategy { abstract public void DoAlgorithm(); } class FirstStrategy: Strategy { override public void DoAlgorithm() { Console.WriteLine("In first strategy"); } } class SecondStrategy: Strategy { override public void DoAlgorithm() { Console.WriteLine("In second strategy"); } } class Context { Strategy s; public Context(Strategy strat) { s = strat; } public void DoWork() { } public void DoStrategyWork() { s.DoAlgorithm(); } } public class Client { public static int Main(string[] args) { FirstStrategy firstStrategy = new FirstStrategy(); Context c = new Context(firstStrategy); c.DoWork(); c.DoStrategyWork(); return 0; } } }