带有委托的观察者模式和使用事件数组的事件

时间:2011-04-29 11:08:06

标签: c# .net observer-pattern

我们有一个管理许多存储数据的队列的类。我希望用户在将新数据添加到每个队列时收到通知。我想使用委托和事件来使用观察者模式。通常对于单个事件和来源,我们会这样做:

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 个答案:

答案 0 :(得分:4)

不,事件不会那样。选项:

  • 创建另一个公开事件的类型,并拥有该类型的数组或集合:

    // 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, ...);
    

我个人觉得每个队列都应该是它自己的对象,但是......让队列管理器公开一个队列集合,每个队列都可以单独订阅。 (即采取第一种方法。)否则你的队列管理员真的做了太多的工作。

答案 1 :(得分:3)

你可以采取两种方法;首先是:

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代码中执行此操作,而在订阅期间我只是lock

答案 2 :(得分:2)

你需要通过实际应用observer pattern来重新考虑这一点,而不是基于模式的模糊概念。

定义您的IObserver和ISubject接口,并尝试了解观察者是什么以及主题是什么。在你的情况下,听起来像队列是主题,不确定观察者在你的领域模型中会是什么。

一旦你这样做,事情将更容易弄明白,而这只是实现你的接口声明的方法的问题,例如你的主题(队列)将只调用notify(并且如果你想使用就引发一个事件)代理人)当事情发生时(项目被添加到队列中)。

希望这有帮助。

答案 3 :(得分:0)

也许您可以使用Event Aggregator pattern

并不是说您需要编写更少的代码,但它可以创建更干净/可维护的代码。

答案 4 :(得分:0)

这是C#中的工作代码。

QueueManger公开可由一个或多个观察者订阅的事件Ne​​wDataAddedEvent。 Queue在数据更改时调用QueueManager上的NewDataAdded()方法。 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);
            }
        }

    }

}