Шаблон наблюдателя с делегатом и событиями, использующими массив событий - PullRequest
2 голосов
/ 29 апреля 2011

У нас есть класс, который управляет многими очередями, в которых хранятся данные. Я хочу, чтобы пользователь получал уведомления при добавлении новых данных в каждую из этих очередей. Я хотел бы использовать шаблон наблюдателя, используя делегат и события. Обычно для одного события и источника мы бы сделали:

public delegate void NewDataAddedDelegate();
public event NewDataAddedDelegate NewDataAdded;

и для наблюдателя:

qManager.NewDataAdded += new qManager.NewDataAddedDelegate(getNewDataFunc);

Но в этом случае мы имеем, скажем, 10 очередей, каждая из которых может принимать данные произвольно. Поэтому мы бы хотели, чтобы функции наблюдателя подписывались на отдельную очередь. Мы думали, что сможем сделать:

public delegate void NewDataAddedDelegate();
public event NewDataAddedDelegate [] NewDataAdded;  // can't do this

и в конструкторе qManager:

NewDataAdded = new NewDataAddedDelegate[numberOfQueues];

и в наблюдателе:

qManager.NewDataAdded[0] += new qManager.NewDataAddedDelegate(getNewDataFunc0);
qManager.NewDataAdded[1] += new qManager.NewDataAddedDelegate(getNewDataFunc1);

но нет, поскольку ожидается, что событие будет типом делегата, а не массивом типа делегата.

Есть идеи, как подойти к этой проблеме?

Ответы [ 5 ]

4 голосов
/ 29 апреля 2011

Нет, события не работают так.Опции:

  • Создайте другой тип, который предоставляет событие и имеет массив или коллекцию этого типа:

    // Preferably *don't* just expose an array...
    public TypeWithEvent[] Queues { get { ... } }
    
    // Subscription:
    qManager.Queues[i].NewDataAdded += ...
    
  • В качестве альтернативыне использовать события, и просто есть метод:

    private NewDataAddededDelegate[] newDataAdded;
    
    public void SubscribeNewDataAddedHandler(int queue, 
                                             NewDataAddedDelegate handler)
    {
        newDataAdded[queue] += handler;
    }
    
    // Subscription
    qManager.SubscribeNewDataAddedHandler(0, ...);
    

Лично мне кажется, что каждая очередь действительно должна быть своим собственным объектом, хотя ... сделать, чтобы менеджер очереди выставлялКоллекция очередей, на каждую из которых можно подписаться индивидуально.(т.е. используйте первый подход.) В противном случае ваш администратор очередей действительно выполняет слишком много работы.

3 голосов
/ 29 апреля 2011

Есть два подхода, которые вы могли бы использовать там;первый должен иметь:

private NewDataAddedDelegate[] queues; // init not shown
public void Subscribe(int index, NewDataAddedDelegate handler) {
    queues[index] += handler;
}

и использовать

obj.Subscribe(index, ...);

, но вы можете подумать о синхронизации и т. д. при подписке.Второй подход заключается в создании класса-оболочки, который имеет событие - тогда вы можете использовать синхронизацию компилятора, что хорошо в C # 4.0:

public class SomeQueue {
    public event NewDataAddedDelegate NewDataAdded;
}

, а затем выставить их, возможно, через индексатор, так что вы

obj.Queues[index].NewDataAdded += ...

Лично я ожидаю, что первое легче.Только синхронизация может быть неприятной.Я делаю это в некотором коде pub-sub, и IIRC я ​​просто lock во время подписки.

2 голосов
/ 29 апреля 2011

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

Определите свои интерфейсы IObserver и ISubject и попытайтесь понять, что такое наблюдатель и каковы субъекты.В вашем случае звучит так, что очереди - это субъекты, не уверенные, какими будут наблюдатели в вашей модели предметной области.

Как только вы это сделаете, все будет легче выяснить, и это просто вопрос реализацииметоды, объявленные вашими интерфейсами, например ваши субъекты (очереди) будут просто вызывать notify (и вызывать событие, если вы хотите использовать делегатов), когда что-то происходит (элемент добавлен в очередь).

Надеюсь, это поможет.

0 голосов
/ 29 апреля 2011

Вот рабочий код в C #.

QueueManger предоставляет событие NewDataAddedEvent, на которое может подписаться один или несколько наблюдателей.Очередь вызывает метод NewDataAdded () в QueueManager при изменении данных.QueueManager уведомляет, есть ли подписчики с параметром Queue.Я надеюсь, что это отвечает на ваш вопрос.

using System;
using System.Collections.Generic;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            QueueManager queueManager = new QueueManager();
            Observer observer = new Observer(queueManager);
            Queue queue1 = queueManager.AddQueue();
            Queue queue2 = queueManager.AddQueue();

            queue1.OnNewDataAdd();
            queue2.OnNewDataAdd();

            Console.ReadLine();
        }


        delegate void NewDataAddedDelegate(Queue queue);


        class Queue
        {
            QueueManager queueManager;
            public string id;
            public Queue(string id, QueueManager queueManager)
            {
                this.id = id;
                this.queueManager = queueManager;
            }

            public void OnNewDataAdd()
            {
                this.queueManager.NewDataAdded(this);
            }
        }

        class QueueManager
        {
            List<Queue> queues = new List<Queue>();

            public Queue AddQueue()
            {
                Queue queue = new Queue((queues.Count + 1).ToString(), this);
                this.queues.Add(queue);
                return queue;
            }

            public event NewDataAddedDelegate NewDataAddedEvent;
            public void NewDataAdded(Queue queue)
            {
                if (NewDataAddedEvent != null)
                    NewDataAddedEvent(queue);
            }
        }

        class Observer
        {
            public Observer(QueueManager queueManager)
            {
                queueManager.NewDataAddedEvent += new NewDataAddedDelegate(queue_NewDataAdded);
            }

            void queue_NewDataAdded(Queue queue)
            {
                Console.WriteLine("Notification to the observer from queue {0}", queue.id);
            }
        }

    }

}
0 голосов
/ 29 апреля 2011

Возможно, вы могли бы использовать шаблон агрегатора событий .

Не то чтобы вам приходилось меньше кодировать, но это могло бы создать более чистый / поддерживаемый код.

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