抽象类中的保护抽象方法或公共抽象方法

9

你好,我有一个抽象类,在其中有一些公共方法和一些抽象方法。

我将这些公共方法放在里面是为了让它们实现派生类的公共方法。

我感到困惑的是,为什么我会希望定义一个公共抽象方法而不是受保护的抽象方法。在抽象类中定义一个公共抽象方法对我来说没有任何意义...因为如果是抽象的,那么它将在派生类中被重写,但是如果定义为公共的,那么在某种程度上将其定义为受保护的更有意义,因为我们知道我们将在派生类中重写它。

在抽象类中定义公共抽象方法是否有问题?哪个更好?为什么?

4个回答

19

这取决于你想要实现什么。例如,你有一个名为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.
    }
}

客户可以打开关闭电视,但不能在屏幕上画图


9
出于与在对象中需要公共方法相同的原因 :) 在此阶段,您只是不知道特定的实现方式。这在具有非常高抽象级别的类中很常见,例如中间件。
编辑:这是100%合法的。您只需要确保它是您想要在每个具体实现中向外界公开的功能。入口点方法(例如:start、execute、parse..)通常属于此类。 UML Examlple of abstract public

2
抽象类本身必须与继承它的类一样可访问。因此,如果继承的类是公共的,则抽象类也必须是公共的。
公共抽象与其他公共方法具有相同的思想:如果您有一个抽象类,您将传递它。因此,如果该方法应从外部调用,则为public。如果该方法仅用于子级和父级之间的通信,则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");
        }
    }

1

TLTR: 因为开闭原则

为什么将抽象成员声明为protected而非public是有意义的呢?据我所见,这是为了隐藏实现细节。如果您想确保类内定义的每个抽象成员的意图被保留,公开一个单一的“入口点”很方便。通常像“Execute”、“Parse”、“Start”这样的方法就是这样的方法,就像@Sam Aleksov已经指出的那样。正是这些公共方法将协调何时以及在什么特定顺序和条件下调用或访问哪些抽象成员,但这种封装的代价是降低了扩展性。

解释:

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

初始实现:

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...
            innerException: 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 _impl;

    public ExceptionHandlerWrapper(ExceptionHandlerBase impl)
    {
        thos._impl= impl;
    }

    protected override void HandleException(Exception ex, Action operation)
    {
        this.BeforeHandleException();
        this._impl.HandleException(ex, operation); // Compile error**
    }
    
    private void BeforeHandleException()
    {
        // do additional stuff
    }
}

正如您所看到的,出现了编译错误,因为ExceptionHandlerBase.HandleException无法从定义它的类外部访问。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接