- PVSM.RU - https://www.pvsm.ru -
Признаюсь честно, описание этого паттерна мне не встречалось, соответственно его название я выдумал. Если у кого есть информация о правильном названии, буду очень рад услышать. Паттерн не привязан к языку но в данной статье я буду использовать C#
.
Картинка для привлечения внимания:
Итак представим себе систему состоящую из сервиса, который предоставляет другим частям системы отслеживать набор объектов. Это может быть сервис симуляции предоставляющий список симулируемых объектов или любой другой похожий.
Объекты порождаемые и уничтожаемые системой:
public interface IObject
{
}
Сервис, предоставляющий доступ к объектам:
public delegate void ServiceChangedHandle(IService sender, IObject item, bool injected);
public interface IService
{
IEnumerable<IObject> Items { get; }
event ServiceChangedHandle OnServiceChanged;
}
Тем системам, которым необходимо работать с объектами, подписываются на событие, чтобы отслеживать появление новых объектов и исчезновение текущих.
Типичный пример слушателя:
public class Listener
{
public void Initialise()
{
foreach (var item in service.Items)
RegisterItem(item);
service.OnServiceChanged += OnServiceChanged;
}
public void Shutdown()
{
service.OnServiceChanged -= OnServiceChanged;
foreach (var item in service.Items)
UnregisterItem(item);
}
private void OnServiceChanged(IService sender, IObject item, bool injected)
{
if (injected)
RegisterItem(item);
else
UnregisterItem(item);
}
private void RegisterItem(IObject item)
{
...
}
private void UnregisterItem(IObject item)
{
...
}
private IService service;
}
При активации слушателя он обрабатывает все объекты которые уже присутствуют в сервисе а после этого подписывается на изменения списка объектов. При завершении работы слушателя необходимо произвести обратные действия.
При многопоточном программировании все усложняется, потому что между опросом и подпиской, список объектов может изменится. Сервис должен будет предоставить объект синхронизации а слушатель заблокирует изменение списка между обходом списка и подпиской.
Сервис с поддержкой многопоточности:
public interface IService
{
...
// Объект для синхронизации
object SyncRoot { get; }
}
Слушатель с поддержкой многопоточного сервиса (Внутренняя синхронизация опущенна):
public class Listener
{
public void Initialise()
{
// Добавляем синхронизацию
lock (service.SyncRoot)
{
foreach (var item in service.Items)
RegisterItem(item);
service.OnServiceChanged += OnServiceChanged;
}
}
public void Shutdown()
{
// Добавляем синхронизацию
lock (service.SyncRoot)
{
service.OnServiceChanged -= OnServiceChanged;
foreach (var item in service.Items)
UnregisterItem(item);
}
}
...
}
Можно немного упростить систему подписки, если гарантировать что в момент подписки и отписки в сервисе нет ни одного объекта. Такую гарантию дать сложно, особенно в системах где время появления сервисов не определенно.
Но можно эмулировать эту гарантию для каждого подписчика, в этом и суть паттерна. При подписке, сервис будет принудительно посылать событие появления объекта для всех уже существующих объектов а при отписке, посылать событие исчезновения. При этом слушатель упрощается, причем для многопоточного и однопоточного варианта он будет выглядеть одинаково.
Подписчик для многопоточного и однопоточного варианта сервиса (Внутренняя синхронизация опущена):
public class Listener
{
public void Initialise()
{
service.OnServiceChanged += OnServiceChanged;
}
public void Shutdown()
{
service.OnServiceChanged -= OnServiceChanged;
}
...
}
Реализации сервиса для однопоточного варианта:
public class Service : IService
{
...
public event ServiceChangedHandle OnServiceChanged
{
add
{
// Эмулируем добавление объектов для подписчика
foreach (var item in items)
value(this, item, true);
// Непосредственная подписка
eventHandle += value;
}
remove
{
// Непосредственная отписка
eventHandle -= value;
// Эмулируем исчезновение объектов
foreach (var item in items)
value(this, item, false);
}
}
private ServiceChangedHandle eventHandle;
private List<IObject> items = new List<IObject>();
}
Как и у любого паттерна у этого варианта слушателя есть свои плюсы, минусы и область применения.
Плюсы:
Минусы:
Из минусов и плюсов можно выделить область применения паттерна:
Всем спасибо за внимание!
Автор: mynameco
Источник [1]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/patterny-proektirovaniya/48185
Ссылки в тексте:
[1] Источник: http://habrahabr.ru/post/201908/
Нажмите здесь для печати.