C # Лучшая практика: централизованный контроллер событий или нет - PullRequest
6 голосов
/ 17 ноября 2008

У меня есть приложение, которое состоит из нескольких различных сборок, одна из которых содержит различные интерфейсы, которым подчиняются классы, и посредством которых классы взаимодействуют через границы сборок. Существует несколько классов событий стрельбы, и несколько, которые заинтересованы в этих событиях.

Мой вопрос таков: является ли хорошей практикой реализация какого-либо центрального EventConsolidator? Это было бы тесно связано, так как для этого нужно было бы знать, что каждый класс (или, по крайней мере, интерфейс) вызывает событие, и каждый потребитель события должен иметь ссылку на EventConsolidator для подписки.

В настоящее время у меня есть ситуация, когда класс A знает класс B (но не C), класс B знает класс C и т. Д. Затем, если C запускает событие, B должен взять его и запустить собственное событие, чтобы A реагировать. Такие цепочки могут быть довольно длинными, и может случиться так, что B заинтересован только в событии, чтобы передать его. Я не хочу, чтобы A знал о C, поскольку это нарушило бы инкапсуляцию.

Что такое хорошая практика в этой ситуации? Централизовать события, или ухмыляться и нести это и определять события в каждом промежуточном классе? Или каковы критерии принятия решения? Спасибо!

Редактировать: Здесь - это еще один вопрос, задающий по существу то же самое.

Ответы [ 6 ]

8 голосов
/ 17 ноября 2008

Вы можете поместить само событие в интерфейс, так что A не нужно знать о C напрямую, а только о том, что оно имеет соответствующее событие. Однако, возможно, вы имеете в виду, что экземпляр A не видит экземпляра C ...

Я бы постарался держаться подальше от централизованной системы событий. Скорее всего, это усложнит тестирование, и, как вы сказали, появится жесткая связь.

Один шаблон, о котором стоит знать, - это упрощение прокси событий. Если B только выставляет событие для прокси его C, вы можете сделать:

public event FooHandler Foo
{
    add
    {
        c.Foo += value;
    }
    remove
    {
        c.Foo -= value;
    }
}

Таким образом, он передает прокси подписку / отписку, а не сам факт создания события. Конечно, это влияет на соответствие требованиям GC, что может быть полезным или нет в зависимости от ситуации. Хотя стоит подумать.

6 голосов
/ 17 ноября 2008

То, что вы можете попробовать, это использовать брокер событий NInject или Unity Application Block .

Это позволяет вам, например:

[Publish("foo://happened")]
public event EventHandler<FooArgs> FooHappened;

[Subscribe("foo://happened")]
public void Foo_Happened(object sender, FooArgs args)
{ }

Если оба объекта создаются через контейнер, события будут подключаться автоматически.

1 голос
/ 17 ноября 2008

Вы можете извлекать объект EventBroker в библиотеке шаблонов и практик M $, если вам нужны централизованные события.

Лично я думаю, что лучше подумать о вашей архитектуре, и, хотя мы используем EventBroker здесь, ни один из нашего нового кода не использует его, и мы надеемся постепенно отказаться от него в один солнечный день.

1 голос
/ 17 ноября 2008

Это было бы очень тесно связано, так как это должно было бы знать каждый класс

Я думаю, что вы ответили на свой вопрос, если считаете, что связь плохая! Передача событий через цепочку потенциальных обработчиков является довольно распространенной моделью во многих средах; Возможно, это не самый эффективный подход, но он позволяет избежать сложности, которая может возникнуть в результате вашего предложенного подхода.

Другой подход, который вы можете использовать, - использовать диспетчер сообщений. Это включает использование общего формата сообщения (или, по крайней мере, общего формата заголовка сообщения) для представления событий, а затем помещение этих сообщений в очередь. Затем диспетчер выбирает каждое из этих событий по очереди (или на основании некоторой расстановки приоритетов) и направляет их непосредственно в требуемый обработчик. Каждый обработчик должен быть зарегистрирован диспетчером при запуске.

В этом случае сообщением может быть просто класс с несколькими конкретными полями в начале. Конкретное сообщение может быть просто производным, или вы можете передать свои специфичные для сообщения данные в качестве параметра «объект» вместе с заголовком сообщения.

1 голос
/ 17 ноября 2008

Я бы, вероятно, попытался помассировать домен, чтобы каждый класс мог напрямую зависеть от соответствующего источника события. Я имею в виду, что задаю вопрос, почему А не знает о С? Может быть, есть D, ожидающий появления?

В качестве альтернативного подхода вы можете рассмотреть архитектуру брокера событий. Это означает, что наблюдатели не знают напрямую об источнике. Вот интересное видео .

0 голосов
/ 29 декабря 2009

у нас есть собственная реализация брокера событий (с открытым исходным кодом) Учебное пособие по адресу: http://sourceforge.net/apps/mediawiki/bbvcommon/index.php?title=Event_Broker

И анализ производительности по адресу: www.planetgeek.ch/2009/07/12/event-broker-performance/

Преимущества по сравнению с CAB: - лучшая регистрация - поддержка расширений - лучшая обработка ошибок - расширяемые обработчики (пользовательский интерфейс, фоновый поток, ...) и еще несколько я не могу вспомнить прямо сейчас.

Ура, Урс

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...