抽象方法使用vs常规方法

Mul*_*der 5 c# abstract-class abstract-methods

我想知道两个约定之间的区别:

  1. 使用抽象方法创建抽象基类,稍后将在派生类上实现该抽象基类.
  2. 在没有抽象方法的情况下创建抽象基类,
    但稍后在派生类的级别上添加相关方法.

有什么不同?

Mat*_*ott 10

与接口非常相似,抽象类旨在为您的类型表达一组已知操作.但是,与接口不同,抽象类允许您实现可由任何派生类型使用的公共/共享功能.例如:

public abstract class LoggerBase
{
  public abstract void Write(object item);

  protected virtual object FormatObject(object item)
  {
    return item;
  }
}
Run Code Online (Sandbox Code Playgroud)

在上面这个非常基本的例子中,我基本上做了两件事:

  1. 定义了我的派生类型将遵循的合同.
  2. 提供一些默认功能,如果需要可以覆盖.

鉴于我知道任何派生类型LoggerBase将有一个Write方法,我可以称之为.以上作为接口的等价物可以是:

public interface ILogger
{
  void Write(object item);
}
Run Code Online (Sandbox Code Playgroud)

作为一个抽象类,我可以提供一个额外的服务FormatObject,可以选择覆盖,比如我写的是ConsoleLogger,例如:

public class ConsoleLogger : LoggerBase
{
  public override void Write(object item)
  {
    Console.WriteLine(FormatObject(item));
  }
}
Run Code Online (Sandbox Code Playgroud)

通过将FormatObject方法标记为虚拟,这意味着我可以提供共享实现.我也可以覆盖它:

public class ConsoleLogger : LoggerBase
{
  public override void Write(object item)
  {
    Console.WriteLine(FormatObject(item));
  }

  protected override object FormatObject(object item)
  {
    return item.ToString().ToUpper();
  }
}
Run Code Online (Sandbox Code Playgroud)

所以,关键部分是:

  1. abstract 类必须继承.
  2. abstract 方法必须在派生类型中实现.
  3. virtual 方法可以在派生类型中重写.

在第二种情况下,因为您不会将功能添加到抽象基类,所以在直接处理基类的实例时无法调用该方法.例如,如果我实施ConsoleLogger.WriteSomethingElse,我无法从中调用它LoggerBase.WriteSomethingElse.


Guy*_*Ari 5

将抽象方法放在基类中然后在子类中实现它们的想法是,您可以使用父类型而不是任何特定的子类。例如,说您要对数组进行排序。您可以将基类定义为类似

abstract class Sorter {
    public abstract Array sort(Array arr);
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以在子类中实现各种算法,例如quicksort,mergesort,heapsort。

class QuickSorter {
    public Array sort(Array arr) { ... }
}

class MergeSorter {
    public Array sort(Array arr) { ... }
}
Run Code Online (Sandbox Code Playgroud)

您可以通过选择算法来创建排序对象,

Sorter sorter = QuickSorter();
Run Code Online (Sandbox Code Playgroud)

现在,您可以通过sorter,而无需揭露它是快速分类的事实。你说要对数组排序

Array sortedArray = sorter.sort(someArray);
Run Code Online (Sandbox Code Playgroud)

这样,实现的细节(使用哪种算法)就从接口与对象分离(它对数组进行排序的事实)。

一个具体的优点是,如果您希望在某个时候使用不同的排序算法,则可以在单行中QuickSort()改为说MergeSort,而无需在其他任何地方进行更改。如果sort()父级中不包含方法,则QuickSorter每次调用时都必须向下转换sort(),然后更改算法将更加困难。