【问题标题】:Protected abstract or public abstract method in abstract class抽象类中受保护的抽象或公共抽象方法
【发布时间】:2015-08-02 20:15:48
【问题描述】:

您好,我有一个抽象类,其中有一些公共方法和一些抽象方法。 我有 public 以便他们实现派生类的常用方法。

让我困惑的是为什么我要定义一个公共抽象方法而不是受保护的抽象方法。在抽象类中定义公共抽象方法对我来说没有任何意义......因为在派生类中,如果是抽象将被覆盖,但同样是如果定义为公共但不知何故定义更有意义它就像我们知道的那样受到保护,我们将在派生类中覆盖它。

在抽象类中将方法定义为公共抽象是错误的吗?哪个更好,为什么?

【问题讨论】:

    标签: c# oop abstract protected


    【解决方案1】:

    TLTR:因为开闭原则

    在我看来,为什么使用抽象成员 protected 而不是 public 是为了隐藏“实现细节”。如果要确保在类中定义每个抽象成员的意图,公开一个单一的“入口点”会很方便。通常,公共方法将协调何时以及什么抽象成员被调用或访问,以及在什么特定的顺序和在什么情况下,但是这一层封装的权衡是你失去了可扩展性属性。

    说明:

    假设我们创建了一个包含多个异常处理程序类的库。

    初步实施:

    namespace MyLibrary;
    
    public abstract class ExceptionHandlerBase
    {
        protected abstract void HandleException(Exception ex, Action operation);
    
        public void Execute(Action operation)
        {
            try {
                operation.Invoke();
            } catch(Exception ex) {
                this.HandleException(ex, operation);
            }
        }
    }
    
    public class InputExceptionHandler: ExceptionHandlerBase
    {
        protected override void HandleException(Exception ex, Action operation)
        {
            throw new Exception(
                message: "Wrong input"   // or whatever...
                inner: ex);
        }
    }
    
    public class DbExceptionHandler : ExceptionHandlerBase
    {
        protected override void HandleException(Exception ex, Action operation)
        {
            Console.WriteLine("Failed to connect to database. Retrying...");
            operation.Invoke();
        }
    }
    

    现在,如果我们想扩展 ExceptionHandlerBase 的行为,我们将看到由于 ExceptionHandlerBase.HandleException 方法的 protected 访问修饰符而受到限制。

    让我们尝试在ExceptionHandlerBase.HandleException方法之前添加一个钩子:

    class ExceptionHandlerWrapper : ExceptionHandlerBase
    {
        readonly ExceptionHandlerBase _base;
    
        public ExceptionHandlerWrapper(ExceptionHandlerBase @base)
        {
            thos._base = @base;
        }
    
        protected override void HandleException(Exception ex, Action operation)
        {
            this.BeforeHandleException();
            this._base.HandleException(ex, operation); // Compile error**
        }
        
        private void BeforeHandleException()
        {
            // do additional stuff
        }
    }
    

    如您所见,存在编译错误,因为无法从定义它的类外部访问ExceptionHandlerBase.HandleException

    【讨论】:

      【解决方案2】:

      出于同样的原因,您希望在对象中使用公共方法 :) 你只是不知道现阶段的具体实现。 它在抽象级别非常高的类中很常见,例如中间件。

      编辑:它是 100% 合法的。您只需要确保它是您希望在每个具体实现中向世界其他地方公开的功能。入口点方法(例如:start、execute、parse..)通常属于这种类型。

      【讨论】:

        【解决方案3】:

        这取决于您想要达到的目标。例如,您有一个 Television 类,它有 3 个方法,TurnOnTurnOffDraw

        您只希望客户TurnOnTurnOff 电视,但只有它的子类应该知道在屏幕上Draw 是什么以及如何。因此,Television 看起来或多或少如下所示。

        public abstract class Television
        {
            public abstract void TurnOn();
        
            public abstract void TurnOff();
        
            protected abstract void Draw();
        }
        

        然后每个公司都有自己的实现。

        public sealed class MyTelevision
            : Television
        {
            public override void TurnOn()
            {
                Console.WriteLine("Turn on my tv");
            }
        
            public override void TurnOff()
            {
                Console.WriteLine("Turn off my tv");
            }
        
            protected override void Draw()
            {
                // code here.
            }
        }
        

        客户可以TurnOnTurnOff 电视,但不能Draw 屏幕上的任何内容。

        【讨论】:

          【解决方案4】:

          抽象类本身必须像继承自它的类一样可访问。所以如果继承的类是公共的,抽象类也必须是公共的。

          Public Abstract 与其他公共方法有相同的想法:如果你有一个抽象类,你将通过这个 arround。所以如果这个方法应该从外部调用,它是公开的。如果该方法仅用于 Child 和 Parent 之间的通信,则 protected 是要走的路。简单示例,将 Main-Method 视为抽象类的用户:

              static void Main(string[] args)
              {
                  Animal cat = new Cat();
                  Animal dog = new Dog();
          
                  cat.Eat();
                  dog.Eat();
          
                  cat.Move();
                  dog.Move();
              }
          
          
              public abstract class Animal
              {
                  public abstract void Eat();
                  protected abstract void ComplexMoving();
          
                  public void Move()
                  {
                      ComplexMoving();
                  }
          
              }
          
              public class Dog : Animal
              {
                  public override void Eat()
                  {
                      Debug.WriteLine("Dog says Namnam");
                  }
          
                  protected override void ComplexMoving()
                  {
                      Debug.WriteLine("Dog no stupid");
                  }
              }
          
              public class Cat: Animal
              {
                  public override void Eat()
                  {
                      Debug.WriteLine("Cat says namnam");
                  }
          
                  protected override void ComplexMoving()
                  {
                      Debug.WriteLine("Cat does a slalom");
                  }
              }
          

          【讨论】:

            猜你喜欢
            • 2016-03-19
            • 1970-01-01
            • 1970-01-01
            • 2018-08-25
            • 2017-06-14
            • 1970-01-01
            • 1970-01-01
            • 2014-03-04
            • 1970-01-01
            相关资源
            最近更新 更多