将多个事件聚合到一个接口中

本文关键字:一个 接口 事件 | 更新日期: 2023-09-27 18:14:22

可以使用什么替代方法来避免同时暴露事件和接口?我有一个类,它有一个确定的生命周期:创建,修改,……客户端(主要是GUIs)需要连接到该类的生命周期中,因此最简单的方法是公开事件,同时我需要将生命周期中发生的一些责任移出类,因此我提出了这个解决方案:

Interface ILifeCycle
{
    void OnCreated(...);
    void OnModified(...);
    // ...
}
classA
{
    private ILifeCycle lifeCycle;
    /// ...
    public event EventHandler Created(object sender, EventArgs args);
    public event EventHandler Modified(object sender, EventArgs args);
    /// ...
    protected void OnCreated()
    {
        lifeCycle.OnCreated(...);
        if(Created!=null)
        Created(this,EventArgs.Empty);
    }
    protected void OnModified()
    {
        lifeCycle.OnModified(...);
        if(Modified!=null)
        Modified(this,EventArgs.Empty);
    }
    /// ...
}

这样做,我可以注入一个Logger实现ILifeCycle,从而将日志记录责任转移到它自己的类,但感觉会有很多重复。你会推荐哪些清洁的替代方案来实现这一目标?

将多个事件聚合到一个接口中

一般来说,InterfaceEvents/Delegates用于两种非常不同的方法。让我们先描述一下它们-

Interface:接口的主要目的是为该接口的所有实现强制一些功能。无论何时你在子类中实现它,你都会重写超类的实现。例如-

interface IA
{
    void test();
}
class A : IA
{
    public void test(){
    }
}
class B : A 
{
    public void test(){
         //you can only go up by calling base.test(), but cannot move down, because you do not know whether there is an implementation down the tree or not. So you cannot call it.
    }
}
class C : B 
{
    public void test(){
         //you can only go up by calling base.test(), but cannot move down, because you do not know whether there is an implementation down the tree or not. So you cannot call it.
    }
}

正如你所看到的,对于接口,你只能回顾过去,而不能展望未来,并假设会有更多的实现。

Events:事件是为不同的目的而创建的。假设你想给开发者一些工具来依赖一些活动并基于这些活动和变化做一些其他活动,最重要的是他们将在未来实现这个。事件不会依赖于你的实现,它们只会订阅它并基于它做一些事情。无论它们是否存在,您自己的实现都不会改变,您自己的代码的行为也不会基于它们而改变。换句话说,你只能沿着树向下移动。基类捕获事件,然后沿着树传播它们。

这些是InterfaceEvents的常用用法,它们就是这样使用的。但这不是完全不可能的编码,这样它将完全依赖于接口,反之亦然,即代码完全依赖于事件,但这不是他们的本意。

在这种情况下:在您的情况下,我认为您正在尝试实现一个模块化系统,该系统将不依赖于彼此,但再次订阅事件。还有其他的体系结构和模式,特别是IOC容器将对您非常有帮助,它将完全依赖于接口,您将不需要事件。一些。net IOC容器是AutoFac, Castle。温莎,MEF

我自己,最喜欢MEF,这是我几年前写的一篇关于MEF的文章,向你展示了如何在容器中注入运行时处理程序-

http://mahmudulislam.me/2012/04/20/1a-managed-extensibility-framework-introduction/

顺便说一句,文章有点旧了,我正在更新这篇。

解决方案与IOC:我给出了一个可能的解决方案与MEF -

Interface ILifeCycle
{
  void OnCreated(...);
  void OnModified(...);
  ...
} 
[Export(typeof(ILifeCycle))] //export our classes for injection
classB : ILifeCycle{
   public void OnCreated(...)
   {
       ....
   }
   public void OnModified(...){
   }
}
[Export(typeof(ILifeCycle))] //export our classes for injection
classC : ILifeCycle{
   public void OnCreated(...)
   {
       ....
   }
   public void OnModified(...){
   }
}
classA
{
  [ImportMany] //get all exported classes for injection
  private IList<ILifeCycle> _observers;
  protecetd void OnCreated()
  {
     //use MEF to build composition and then do the following
     foreach(var o in _observers){
        o.OnCreated(...);
     }
  }
  protecetd void OnModified()
  {
     //use MEF to build composition and then do the following
     foreach(var o in _observers){
        o.OnModified(...);
     }
  }
  ...
}

这是一个非常基本的解决方案。但在你的情况下,你可能想要使用异步编程。因为事件和接口之间有很大的区别。默认情况下,事件处理程序在单独的线程中调用,因此它不会停止调用者,但接口实现将挂起调用者,直到方法完成。因此,请确保使用异步编程不会阻塞主进程。

使用Async和Await进行异步编程(c#和Visual Basic)

我不确定我理解你,但我认为你担心不同类型的重复实现ILifeCycle。因此,您可以利用继承:

abstract class LifeCycleBase
{
  public void OnCreated(...)
  {
        .....
  }
  public void OnModified(...);
  {
        .....
  }
  ...
}
class LifeCycleLoger : LifeCycleBase
{
  public void OnCreated(...)
  {
     ....
     base.OnCreate();
  }
....
}