Допустим у меня есть класс A. В классе А есть набор эвентов, которые отражают какие либо изменения внутри - изменения коллекций, изменение основных свойств/состояния. И у объекта есть свойство - объект класса B, который должен следить за этими состояниями и производить какую либо работу проанализировав набор всех изменений.
Логично чтобы при создании объекта класса B, передавать ему в конструктор ссылку на объект класса A и привязываться к событиям.
Интересует есть какие либо другие способы, реализации или паттерны.
Ответ
Интересует есть какие либо другие способы, реализации или паттерны
В С# паттерн "наблюдатель" может быть реализован многими способами, например:
На основе делегата
На основе события
При помощи строго типизированного интерфейса
При помощи специальных интерфейсов IObserver/IObservable
На основе делегата
Решение на основе делегата предствляет собой классических колбек. Преимуществом данного метода является отсутствие явного, типизированного обработчика события (взаимоотношение между поставщиком и потребителем события никак не регламентируются) и простота метода – при возникновении события, метод класса Consumer вызывает аргумент-делегат:
class Consumer
{
public void Event(Action callback)
{
...
callback();
}
}
При возникновении события будет вызван делегат act и весь его invocation list, таким образом поддерживается множественность обработки события.
На основе события
Метод похож на предыдущий, но с той разницей, что позволяет организовать подписку на события любому количеству обработчиков (без моделирования отношения 1:1 как в предыдущем методе) либо не иметь обработчиков вовсе.
class Consumer
{
public event EventHandler
void RaiseEvent()
{
// Не самый потокобезопасный код
if (Event != null) {
Event.Invoke(this, new EventArgs());
}
}
}
public class Program
{
public static void Main()
{
Consumer consumer = new Consumer();
consumer.Event += (object sender, EventArgs args) => { /* */ };
consumer.Event += (object sender, EventArgs args) => { /* */ };
}
}
Метод похож на предыдущий но не дает гарантий на присутствие хотя бы одного обработчика.
При помощи строго типизированного интерфейса
В этом методе потребитель обрабатывает события поставщика при помощи определенного интерфейса обработчика, строго формализуя отношения между поставщиком и потребителем.
interface IEventHandler
{
void FirstEventHandler();
void SecondEventHandler();
}
class Supplier : IEventHandler
{
public void FirstEventHandler()
{
/* Обработчик события */
}
public void SecondEventHandler()
{
/* Обработчик другого события */
}
}
class Consumer
{
IEventHandler _supplier;
public void Subscribe(IEventHandler supplier)
{
_supplier = supplier;
}
void RaiseFirstEvent()
{
_supplier.FirstEventHandler();
}
void RaiseSecondEvent()
{
_supplier.SecondEventHandler();
}
}
public class Program
{
public static void Main()
{
Consumer consumer = new Consumer();
Supplier supplier = new Supplier();
consumer.Subscribe(supplier);
}
}
Это почти классическая реализация паттерна подписчик в C# (и паттерна "делегат" в Objective-C с той лишь разницей, что все обработчики должны быть строго определены).
Реализация этого метода требует пристального наблюдения на предмет нарушения SRP, так и согласованности событий поставщика.
При помощи специальных интерфейсов IObserver/IObservable
Начиная с .NET 4 доступны специальные интерфейсы IObserver/IObservable для реализации паттерна наблюдатель для последовательностей событий
class Data {
}
class Consumer : IObserver
{
public void OnCompleted()
{
}
public void OnError(Exception e)
{
}
public void OnNext(Data data)
{
// Обработка новых данных
}
}
class Supplier : IObservable
{
List
class Unsubscriber : IDisposable
{
private List
public Unsubscriber(List
public void Dispose()
{
if (_observer != null && _observers.Contains(_observer))
_observers.Remove(_observer);
}
}
public IDisposable Subscribe(IObserver observer)
{
_subscribers.Add(observer);
return new Unsubscriber(_subscribers, observer);
}
void RaiseEvent()
{
foreach (var subscriber in _subscribers) {
subscriber.OnNext(new Data());
}
}
}
public class Program
{
public static void Main()
{
Consumer consumer = new Consumer();
Supplier supplier = new Supplier();
supplier.Subscribe(consumer);
}
}
Комментариев нет:
Отправить комментарий