Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Design Patterns via C#.pdf
Скачиваний:
153
Добавлен:
17.03.2016
Размер:
13.25 Mб
Скачать

245

Известные применения паттерна в .Net

Паттерн Observer, выражен в языке C# в виде идеи использования функциональноориентированного стереотипа - делегата (delegate) и языковой конструкции - события (event), которая в свою очередь строится на использовании делегата. Так же имеется выражение паттерна Observer в FCL (Framework Class Library) виде двух интерфейсов (interface) - IObservable<out T> и IObserver<in T>.

Ниже с использованием диаграмм языка DSL представлена структура паттерна Observer.

Пример кода, демонстрирует использование интерфейсов IObservable<out T> и IObserver<in T>.

Реализация подписчика:

class ConcreteObserver : IObserver<string>

{

string name;

string observerState; IDisposable unsubscriber;

public ConcreteObserver(string name, IObservable<string> subject)

{

this.name = name;

unsubscriber = subject.Subscribe(this);

}

// Реализация интерфейса IObserver<T> public void OnCompleted()

{

unsubscriber.Dispose();

}

public void OnError(Exception error)

{

246

Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Observer {0}, Error: {1}", name, error.Message); Console.ForegroundColor = ConsoleColor.Gray;

}

// Аналог Update(argument) - модель проталкивания. public void OnNext(string value)

{

observerState = value;

Console.WriteLine("Observer {0}, State = {1}", name, observerState);

}

}

Реализация издателя:

class ConcreteSubject : IObservable<string>, IDisposable

{

public string State { get; set; }

List<IObserver<string>> observers = new List<IObserver<string>>();

public void Notify()

{

foreach (IObserver<string> observer in observers)

{

if (this.State == null)

observer.OnError(new NullReferenceException());

else

observer.OnNext(this.State); // Модель проталкивания.

}

}

//Реализация интерфейса IObservable<T>

//(UnSubscribe выполняется через IDisposable)

///<summary>

///Подписать подписчика.

///</summary>

///<param name="observer">Конкретный подписчик</param>

///<returns>Объект отписывающий подписанного подписчика</returns> public IDisposable Subscribe(IObserver<string> observer)

{

if (!observers.Contains(observer)) observers.Add(observer);

return new Unsubscriber(observers, observer);

}

//Отписать всех подписчиков. public void Dispose()

{

observers.Clear();

}

//Nested Class

class Unsubscriber : IDisposable

{

List<IObserver<string>> observers;

247

IObserver<string> observer;

public Unsubscriber(List<IObserver<string>> observers, IObserver<string> observer)

{

this.observers = observers; this.observer = observer;

}

public void Dispose()

{

if (observers.Contains(observer)) observers.Remove(observer);

else

observer.OnError(new Exception("Данный подписчик не подписан"));

}

}

}

Использование:

class Program

{

static void Main()

{

// Создание издателя.

ConcreteSubject subject = new ConcreteSubject();

// Создание подписчиков.

ConcreteObserver observer1 = new ConcreteObserver("1", subject); ConcreteObserver observer2 = new ConcreteObserver("2", subject); ConcreteObserver observer3 = new ConcreteObserver("3", subject); ConcreteObserver observer4 = new ConcreteObserver("4", subject);

// Подписание подписчиков на издателя с получением объекта для отписки.

IDisposable unsubscriber1 = subject.Subscribe(observer1); IDisposable unsubscriber2 = subject.Subscribe(observer2); IDisposable unsubscriber3 = subject.Subscribe(observer3); IDisposable unsubscriber4 = subject.Subscribe(observer4);

using (subject)

{

//Попытка предоставить подписчикам некорректное состояние. subject.State = null;

subject.Notify();

Console.WriteLine(new string('-', 70) + "1");

//Отписка первого подписчика через

//ConcreteSubject.Unsubscriber.Dispose()

using (unsubscriber1)

{

// Попытка предоставить подписчикам корректное состояние. subject.State = "State 1 ...";

subject.Notify();

}

Console.WriteLine(new string('-', 70) + "2");

//State 2 - получат только три подписчика

//которые остались подписанными.

248

subject.State = "State 2 ..."; subject.Notify();

Console.WriteLine(new string('-', 70) + "3");

//Отписка второго подписчика через ConcreteObserver.OnCompleted() observer2.OnCompleted();

//State 3 - получат только 2 подписчика

//которые остались подписанными.

subject.State = "State 3 ..."; subject.Notify();

} // observers.Clear()

Console.WriteLine(new string('-', 70) + "4");

//Попытка отписать уже отписанного подписчика, обрабатывается в

//ConcreteSubject.Unsubscriber.Dispose()

observer4.OnCompleted();

//Delay.

Console.ReadKey();

}

}

Результат работы программы:

См. Пример к главе: \019_Observer\003_IObserver

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]