Aggregate multiple events into one interface

What alternative can one use to avoid exposing both events and an interface. I have a class that has a determined life cycle: created, modified, ... clients mainly GUIs need to hook up into the life cycle of that class so the simplest way to do it is to expose events, at the same time I need to move some responsibilities -that happen during the life cycle- out of the class so I came up with this solution:

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

Doing this I can inject a Logger that implements ILifeCycle , and so move the logging responsibility to its own class, but it feels like it's going to be a lot of repetition. What clean alternatives would you recommend to achieve this?


In general Interface and Events/Delegates are used for two very different kinds of approach. Lets describe them each first -

Interface : The main purpose of interface is that it enforces some functionality to all implementations of that interface. And whenever you implement it in a subclass, you override the implementation of the super class. For example -

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.
    }
}

As you can see, with interface you can only look back but cannot look forward and assume there will be any more implementations.

Events : Events are created for a different purpose. lets just say you want to give the developers some facility to rely on some activities and do some other activities based on that activities and changes, and most importantly they will be implement this in future. The events will not depend on your implementation, they will just subscribe to it and do something based on that. Whether they exists or not, your own implementation does not change or the behavior of your own code does not changes based on them. In other words, you can only move down the tree. The base class captured the event and then propagates them down the tree.

These are the usual uses of Interface and Events and they are meant to be used that way. But its not completely impossible to code such that it will entirely depend on interface and vice versa, ie code entirely dependent on events but that is not the way they are meant to be.

In This Case : In your case, I am thinking you are trying to achieve a modular system that will not depend on each other but again subscribe to events. There are other architectures and patterns for this, specially IOC containers will be a very helpful for you, that will entirely be interface dependent, you will not need events. Some .net IOC containers are AutoFac, Castle.Windsor, MEF

I myself, like MEF the most, here is a post on MEF that I wrote few years back, shows you how you can inject run-time handlers inside a container -

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

BTW, article is a bit old, I am working on updating this one.

Solution with IOC : I am giving a probable solution with 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(...);
     }
  }
  ...
}

This is a very basic solution. But in your case you might wanna make use of asynchronous programming. Because there is very big difference between Events and Interfaces. By default, events handlers are call in a separate thread and thus it does not halt the caller, but interface implement will hang the caller until the method finishes. So make sure you use asynchronous programming to not block your main process.

Asynchronous Programming with Async and Await (C# and Visual Basic)


I'm not sure I understood you well but I think you worry about repetitions in different types implementing ILifeCycle . So, you can take advantage of inheritance:

abstract class LifeCycleBase
{
  public void OnCreated(...)
  {
        .....
  }
  public void OnModified(...);
  {
        .....
  }
  ...
}

class LifeCycleLoger : LifeCycleBase
{
  public void OnCreated(...)
  {
     ....
     base.OnCreate();
  }
....
}
链接地址: http://www.djcxy.com/p/82264.html

上一篇: Umbraco中的依赖注入或单元测试

下一篇: 将多个事件合并到一个接口中