类是否为另一个类注册事件处理程序是不好的做法?

时间:2018-05-31 00:06:41

标签: c# events event-handling

事件订阅者是否应该始终注册事件处理程序,或者其他类是否可以执行此操作?

示例:

{{1}}

2 个答案:

答案 0 :(得分:0)

  

事件订阅者是否应始终注册事件处理程序,或者是   另一个班级可以做到吗?

这个设计本身并没有什么本质上的错误,但它实际上取决于你的架构以及你想要它的可扩展性和分离性。

请注意,没有与Glue提出的通用假设的背景信息,因此很难说清楚您的确切要求。

...

现在,我很少编写传统事件,并倾向于使用更现代的Pub / Sub Producer / Consumer Decoupled Messages Event Aggregator方法(取决于您使用的框架) )。消费者可以随意订阅,生产者可以随意发布,而无需事先了解彼此。 Martin Follower在他的网站上更详细地介绍了这种模式。

更重要的是,分离消息(和亲属)的优势在于,消费者可以订阅对话,而无需事先知道生产者是谁,这样可以更好地decoupling,从而创造更多可维护和可扩展的系统。如果系统变得足够大,将类推送到Microservices可能会少得多痛苦。

说这个,如果这只是一个非常简单的实现(和紧密耦合的实现),标准的香草冰淇淋风味的.NET事件并让你的订阅者注册事件处理程序没有任何问题,尽管你必须再次将此分解为您设计中最合乎逻辑的问题。

我应该让SoundManager知道一只狗及其树皮。或者你的狗类应该注册给声音管理员。你的设计直觉应该引领方式

无论如何,祝你好运。

答案 1 :(得分:0)

程序化,没有错,会为你顺利工作。

事实上,你需要在EventSubscriber方法的情况下这样做  (Handler)应在Event上调用,不具有EventPublisher类的对象。

如何订阅事件是主观的事情,它取决于你的所有流量和舒适度。

但据我所知,订阅者类订阅活动使代码更具可读性和易于理解

你看到订阅任何类的事件,订阅者类必须有该类的对象,但在你的例子中它没有。

一般来说,当订阅者类本身拥有发布者类的对象时,人们会以这种方法设计体系结构。这种设计在某些流程中有其自身的优点,请参见下面的示例

public class EventPublisher
{
    public event EventHandler HeavyLogicDone;

    public void ExposedMethod(string subScriberSpecificData)
    {
        Thread logicCaller = new Thread(() => HeavyLogic(subScriberSpecificData));
        logicCaller.Start();
    }

    private void HeavyLogic(string subScriberSpecificData)
    {
        //logic which may take time
        if (HeavyLogicDone != null)
            HeavyLogicDone(this, new EventArgsClass(subScriberSpecificData));
    }
}

此处EventPublisher类具有公开的功能,应该由EventSubscriber调用,但由于此方法可能需要一些时间,因此它是用线程编写的。

现在问题,因为它在线程中,这个方法的调用将在启动线程后很快返回,订阅者无法启动其依赖于此方法的结果的功能,它必须等待。因此,要通知订阅者已完成任务,则会发生一个事件。

public class EventSubscriber
{
    string currentData = "";
    public EventSubscriber(EventPublisher eventPublisher, string data)
    {
        currentData = data;
        eventPublisher.HeavyLogicDone += eventPublisher_HeavyLogicDone;
        eventPublisher.ExposedMethod(currentData);
        //Contineous without waiting for heavy logic to compelete
    }

    void eventPublisher_HeavyLogicDone(object sender, EventArgs e)
    {
        if(((EventArgsData)e).subScriberSpecificData == currentData)
        {
           //Do further task which is dependant to result of logic
           //if now subscriber doesn't need to listen this event anymore
           ((EventPublisher)sender).HeavyLogicDone -= eventPublisher_HeavyLogicDone;
        }
    }
}

正如您所知,何时订阅某个活动以及何时取消订阅,订阅者现在可以完全控制。

但是,如果你这样做的话。

static void Main(string[] args)
{
    EventSubscriber subscriber1 = new EventSubscriber("sub1");
    EventSubscriber subscriber2 = new EventSubscriber("sub2");
    EventPublisher pub = new EventPublisher();
    pub.HeavyLogicDone += subscriber1.eventPublisher_HeavyLogicDone;
    pub.HeavyLogicDone += subscriber2.eventPublisher_HeavyLogicDone;
    pub.ExposedMethod("sub1");
    pub.ExposedMethod("sub2");
}

第一个问题:正如您所看到的,每次创建Subscriber实例时,您都必须明确地为其订阅并为当前订阅者调用发布者的方法。这是耦合代码,你需要每次都这样做。

和订阅者类

public class EventSubscriber
{
    string currentData = "";
    public EventSubscriber(string data)
    {
        currentData = data;
    }
    public void eventPublisher_HeavyLogicDone(object sender, EventArgs e)
    {
        if(((EventArgsData)e).subScriberSpecificData == currentData)
        {
           //Do further task which is dependant to result of logic

           //if now subscriber doesn't need to listen this event anymore
           ((EventPublisher)sender).HeavyLogicDone -= eventPublisher_HeavyLogicDone;
        }
    }
}

第二个问题:由于订阅不能控制订阅者类,因此只能使用订阅者类进行取消订阅。代码将很难理解。