- •А.А. Волосевич
- •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. Архитектура прогРаммного Обеспечения
- •«Клиент-сервер»
- •Архитектура, основанная на использовании компонентов
- •Многоуровневая архитектура
- •Шина сообщений
- •Выделенное представление
- •Объектно-ориентированная архитектура
- •Архитектура, ориентированная на сервисы
Наблюдатель (Observer)
Шаблон Наблюдатель определяет отношение между объектами таким образом, что когда один из объектов меняет своё состояние, все другие объекты получают об этом уведомление.
Иллюстрацией применения шаблона Наблюдатель служит знакомая по языку C# система событий. Один объект публикует событие, остальные объекты могут подписаться на событие и получать уведомление о его наступлении. Собственно, основное назначение шаблона Наблюдатель – это реализация системы работы с событиями.
Как и в случае с шаблоном Посредник, дизайн шаблона Наблюдатель предполагает наличие двух выделенных классов. Объект класса Subject изменяет своё состояния, и именно эти изменения предполагается отслеживать. Объекты (их может быть несколько) класса Observer могут подписываться на отслеживание изменений. Класс Subject располагает закрытым событием с именем Notify. Как только Subject изменяет своё состояние, событие активируется. При этом вызывается метод Update() подписчиков, которому передаётся состояние объекта Subject. Метод Update() предварительно регистрируется в Subject при помощи операции Attach().
Рис. 22. Дизайн шаблона Наблюдатель.
Далее приводится пример кода, демонстрирующего реализацию шаблона Наблюдатель. Заметим, что в примере намеренно не используются события.
using System;
using System.Collections.Generic;
// аналог Subject
public abstract class Stock
{
private double price;
private readonly IList<IInvestor> investors =
new List<IInvestor>();
public double Price
{
get { return price; }
set
{
if (price != value)
{
price = value;
Notify();
}
}
}
public string Symbol { get; private set; }
protected Stock(string symbol, double price)
{
Symbol = symbol;
this.price = price;
}
public void Attach(IInvestor investor)
{
investors.Add(investor);
}
public void Detach(IInvestor investor)
{
investors.Remove(investor);
}
public void Notify()
{
foreach (var investor in investors)
{
investor.Update(this);
}
}
}
public class IBM : Stock
{
public IBM(double price) : base("IBM", price) { }
}
// интерфейс, аналогичный IObserver
public interface IInvestor
{
void Update(Stock stock);
}
// конкретный обозреватель
public class Investor : IInvestor
{
public string Name { get; private set; }
public Stock Stock { get; set; }
public Investor(string name)
{
Name = name;
}
public void Update(Stock stock)
{
Console.WriteLine("Notified {0} of {1}'s change to {2:C}",
Name, stock.Symbol, stock.Price);
}
}
public class ObserverExample
{
private static void Main()
{
var ibm = new IBM(120.00);
ibm.Attach(new Investor("Sorros"));
ibm.Attach(new Investor("Berkshire"));
ibm.Price = 120.10;
ibm.Price = 121.00;
ibm.Price = 120.50;
ibm.Price = 120.75;
Console.ReadKey();
}
}