什么时候应该使用继承而不是实用程序类?

时间:2015-03-31 09:32:15

标签: c# inheritance

我正在开发一个使用Canvas个对象的项目。我想添加一些功能来操纵它们。

到现在为止,我将它们添加到CanvasUtils类中,但现在我意识到我实际上可以创建一个CustomCanvas类,它将继承Canvas并实现新的功能。

我觉得第二种方式更直观,但我不确定它是否是最好的选择。 例如,如果我继续向CustomCanvas类添加新方法,那么在某些时候它会变得很大,而我可以很容易地将一个utils类分成几个。

同样,Utils类听起来更独立,可以扩展到我。例如,如果我想将某些功能扩展到Panel个对象(Canvas继承自Panel),我认为使用Utils更容易做到这一点类,因为您只需要将Canvas引用更改为Panel

我的问题是:

  1. 是每种方法的优点和缺点
  2. 何时我应该使用哪一个?

2 个答案:

答案 0 :(得分:2)

如果要添加新功能,则应扩展该类。您将能够添加自己的状态以及与它们交互的方法。但是,您无法将此功能添加到现有对象。

如果您只是编写使用现有功能的快捷方式,那么您可以使用Extension Methods添加功能而无需扩展类。例如......

public static class PanelExtensions    
{
    public static void DoSomething(this Panel panel) 
    {
        panel.SomePanelMethod();
        panel.SomeOtherPanelMethod();
    }
}

然后使用它......

Panel myPanel = new Panel();
myPanel.DoSomething();

这种方法的优点是这些方法可用于现有面板,并且它们也将被继承(因此您的Canvas对象也将接收这些方法)。

注意,为了使用扩展方法,您需要在文件顶部有一个using语句,引用它们所在的命名空间。

答案 1 :(得分:1)

这取决于您要实现的目标以及实现新功能所需的内容:

  1. 如果您有无状态方法不需要与对象关联的任何其他信息,那么您可以继续使用Util方法或将它们转换为Extension methods,这将为您提供类似继承的感觉使用和松散耦合的Util类:

    public static class CanvasExtensions
    {
        public static void TransformElements(this Canvas canvas,
            Action<CanvasElement> transform)
        {
            ...
            foreach(var elem in canvas.Children)
            {
                transform(elem);
            }
            ...
        }
    }
    
  2. 如果您需要将某些信息与您操作的对象相关联,那么:

    • 如果对象的行为受到其他功能的深刻影响(如其他标准方法可以否定新功能)以允许基本功能覆盖,则可以继承该类:

      public class DeeplyAffectedCanvas : Canvas
      {
          private IDictionary<CanvasElement, Action> m_dictionary;
      
          public void SpecialTransform(CanvasElement elem, Action transform) { }
      
          public override void Resize() 
          { 
              // Resize, for example, have to take into account
              // the special operation
          }
      }
      
    • 或创建一个包装器,当附加行为不会对包装对象造成太大影响时,它会公开原始对象(Panel):

      public class Wrapper<T>
      {
         public Wrapper(T wrapped)
         {
             this.Wrapped = wrapped;
         }
      
         public T Wrapped { get; private set; }
      
         public implicit operator T (Wrapper<T> wrapper)
         {
             return wrapper.Wrapped;
         }
      }
      
      public class WrappedCanvas : Wrapper<Canvas>
      {
          private Object data;
          public void SafeTransform(...);
      }