【问题标题】:How to refactor duplicate event handling code如何重构重复的事件处理代码
【发布时间】:2010-11-23 00:06:49
【问题描述】:

我有以下类可以让某些对象订阅更改事件。问题是我还有 B 类和 C 类,它们需要允许对象订阅相同类型的功能的功能。我们当然不想复制和粘贴这种行为。

我们考虑过从一个公共基类继承,但我们所有的类(包括 A、B 和 C)都已经从一个公共 BaseClass 继承。而且我们不想将此行为添加到 BaseClass,因为从 BaseClass 继承的其他类 E、F、G 不需要此行为。

有没有更好的解决方案?

public class A : BaseClass
{

    /*other properties and code */

    public event EventHandler OnChange;
    private bool _hasChanged;
    public bool HasChanged
    {
        get { return _hasChanged; }
        set
        {
            _hasChanged = value;
            //only need to notify when we've changed.
            if (value)
            {
                if (OnChange != null)
                    OnChange(this, EventArgs.Empty);
            }
        }
    }
}

【问题讨论】:

    标签: c# inheritance code-duplication


    【解决方案1】:

    考虑一种面向方面的编程方法,就像这个PostSharp example 中使用的那样。它允许你使用属性注入那种样板代码。

    如果您创建了适当的方面,那么您可以编写如下代码:

    public class A : BaseClass
    {
        public event EventHandler OnChanged;
    
        [ChangedNotify("OnChanged")]
        public bool HasChanged { get; set; }
    }
    

    或者,如果想法是为多个属性设置一个 OnChange 事件,您可以将其硬编码到方面,将您的代码减少到

    public class A : BaseClass
    {
        [NotifyOnChanged]
        public bool HasChanged { get; set; }
    }
    

    【讨论】:

      【解决方案2】:

      如果我们暂时不使用继承会怎样?

      1- 假设,不是从公共基类继承,而是将需要事件机制的客户端类与实现事件机制的对象组合起来。

      假设我们的类是

       public class EventNotifier
      {
          public event EventHandler OnChange;
          private bool _hasChanged;
          public bool HasChanged
          {
              get { return _hasChanged; }
              set
              {
                  _hasChanged = value;
                  //only need to notify when we've changed. 
                  if (value)
                  {
                      if (OnChange != null)
                          OnChange(this, EventArgs.Empty);
                  }
              }
          }
      }
      

      2-

       public class A
      {
          private EventNotifier eventNotifier;
          public EventNotifier MyEventNotifier { get { return eventNotifier; } }
      
          public A()
          {
              eventNotifier = new EventNotifier();
          }
      
      
      }
      

      3- 现在您的 A 类用户(继承/组合的 A 类)

      这是用于如果 B 包含 A

       public class b
      {
          A obj ;
          public b()
          {
              obj = new A();
              obj.MyEventNotifier.OnChange += new EventHandler(delegate { Console.WriteLine("Hi"); });
              obj. MyEventNotifier.HasChanged = true;
          }
      }
      

      【讨论】:

      • 这是完美的。没有继承混乱,它更易于维护。谢谢。
      • @Riz 我一定遗漏了一些东西,但是鉴于您最初的问题,A 的用户将如何订阅 OnChange 事件?它被这种设计封装。您的原始问题显示了一个公开 OnChanged 事件的类。
      • @chibacity - 是的,我完全错过了上面的 eventNotifier 字段是私有的这一事实。我以为这是公开的,这就是我计划制作的。如果您发现这种方法有问题,请告诉我。我对您的回答的问题是,每次我们想要添加一个需要类共享的功能时,我们必须创建一个类并将其放入继承层次结构中,然后事情很快就会变得一团糟。
      • @Riz 尽管从 API 的角度来看,“A.EventNotifier.OnChanged”是不寻常的,并且存在可发现性问题(有点精神上的减速带),但组合通常应该比继承更重要设计工具。
      • @Riz,@chibacity:你见过eventnotifier类中的HasChanged方法吗,A的用户应该调用这个方法。
      【解决方案3】:

      您可以考虑在 BaseClass 和 A、B、C 之间引入一个包含常见行为的中间类。这样您就不会污染不需要该行为的 E、F、G。

                   BaseClass
        -----------------------------
        |                           |
      -----                   NotifyBaseClass
      E,F,G                         |
                                  -----
                                  A,B,C
      

      NB 虽然 AOP 看起来不错,但我在尝试让 Postsharp 与其他技术(例如MS 代码分析和 MSBuild。

      【讨论】:

        【解决方案4】:

        为可通知对象创建一个子类可能是可行的方法,但如果将方面以这种方式乘以各种不同的类,则可能会很棘手。另一种方法是将其包含在您的基类中并为其定义一个接口,然后您可以简单地为相关类添加接口。

        运行时,您只需检查它是否是 IChangeable(或其他),然后只连接到事件

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2020-01-02
          • 1970-01-01
          • 2012-12-11
          • 1970-01-01
          • 1970-01-01
          • 2011-08-03
          • 1970-01-01
          相关资源
          最近更新 更多