Объединить несколько событий в один интерфейс

1

Какую альтернативу можно использовать, чтобы избежать разоблачения как событий, так и интерфейса. У меня есть класс, который имеет определенный жизненный цикл: созданный, измененный,... клиенты в основном GUIs должны подключаться к жизненному циклу этого класса, поэтому самый простой способ сделать это - разоблачить события, в то же время мне нужно для выполнения некоторых обязанностей -that происходят в течение жизни cycle- из класса, поэтому я придумал это решение:

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, и поэтому переносит ответственность за регистрацию в свой класс, но похоже, что это будет много повторений. Какие чистые альтернативы вы бы рекомендовали достичь?

  • 0
    Я думаю, что вы можете использовать внедрение зависимостей в своем основном классе и вызывать либо функцию статического журнала, либо внедрить функцию в соответствии с приведенным здесь примером stackoverflow.com/questions/14301389/… - что поможет устранить чувство повторения.
  • 0
    @Mauro Проблема заключается в том, чтобы иметь дело с одной и той же концепцией (представленной как интерфейсом, так и EventHandler), но с другой внешностью.
Показать ещё 6 комментариев
Теги:
events
design
interface

2 ответа

1
Лучший ответ

В общем Interface и Events/Delegates используются для двух очень разных видов подхода. Давайте сначала опишем их -

Интерфейс. Основной целью интерфейса является то, что он обеспечивает некоторую функциональность для всех реализаций этого интерфейса. И всякий раз, когда вы реализуете его в подклассе, вы переопределяете реализацию суперкласса. Например -

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

Как вы можете видеть, с интерфейсом вы можете только оглянуться назад, но не можете рассчитывать на будущее и предположить, что будет еще больше реализаций.

События: События создаются для другой цели. позволяет просто сказать, что вы хотите дать разработчикам некоторую возможность полагаться на некоторые действия и выполнять некоторые другие действия, основанные на этих действиях и изменениях, и, самое главное, они будут реализовывать это в будущем. События не будут зависеть от вашей реализации, они просто подпишутся на нее и сделают что-то на этом основании. Независимо от того, существуют они или нет, ваша собственная реализация не изменяется или поведение вашего собственного кода не изменяется на их основе. Другими словами, вы можете двигаться только по дереву. Базовый класс захватил событие, а затем распространил его по дереву.

Это обычное использование Interface и Events и они предназначены для использования таким образом. Но его невозможно полностью закодировать таким образом, чтобы он полностью зависел от интерфейса и наоборот, то есть код, полностью зависящий от событий, но это не так, как они должны быть.

В этом случае: в вашем случае я думаю, что вы пытаетесь создать модульную систему, которая не будет зависеть друг от друга, но снова подпишитесь на события. Для этого существуют другие архитектуры и шаблоны, особенно контейнеры IOC будут очень полезны для вас, которые будут полностью зависимы от интерфейса, вам не понадобятся события. Некоторые контейнеры.net IOC - это AutoFac, Castle.Windsor, 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 (С# и Visual Basic)

  • 0
    Да, события и интерфейсы - разные понятия, но оба могут использоваться для решения одной и той же проблемы, но с точки зрения пользовательского интерфейса удобнее использовать События, в то время как в моем случае для моей доменной модели предпочтительнее использовать именованное поведение (SecurityChecker, Logger .. .) который перехватывает эти события, и здесь возникает необходимость в явном интерфейсе, поэтому приведем пример того, как мы можем использовать МОК для достижения этой цели?
  • 0
    @ anouar.bagari Обновленный ответ с разделом - Solution with IOC , оно не является надежным доказательством, оно даст вам некоторое представление о том, как это можно сделать с помощью MEF.
0

Я не уверен, что понял вас хорошо, но, думаю, вы беспокоитесь о повторениях в разных типах, реализующих ILifeCycle. Таким образом, вы можете воспользоваться наследованием:

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

class LifeCycleLoger : LifeCycleBase
{
  public void OnCreated(...)
  {
     ....
     base.OnCreate();
  }
....
}
  • 0
    ILifeCycle является агрегированной формой EventHandler Created(object sender, EventArgs args) и EventHandler Modified(object sender, EventArgs args) поэтому любая модификация будет иметь влияние на обе стороны, это мое беспокойство

Ещё вопросы

Сообщество Overcoder
Наверх
Меню