抽象方法使用vs常规方法

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

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

有什么不同?

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

public abstract class LoggerBase { public abstract void Write(object item); protected virtual object FormatObject(object item) { return item; } } 

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

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

鉴于我知道任何派生类型的LoggerBase都有一个Write方法,我可以调用它。 以上作为接口的等价物可以是:

 public interface ILogger { void Write(object item); } 

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

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

通过将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(); } } 

因此,关键部分是:

  1. 必须inheritanceabstract类。
  2. 必须在派生类型中实现abstract方法。
  3. 可以在派生类型中覆盖virtual方法。

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

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

 abstract class Sorter { public abstract Array sort(Array arr); } 

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

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

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

 Sorter sorter = QuickSorter(); 

现在你可以通过sorter ,而不会暴露引擎盖下它是一个快速排序的事实。 要对数组进行排序

 Array sortedArray = sorter.sort(someArray); 

通过这种方式,实现的细节(您使用的算法)与对象的接口(它对数组进行排序)分离。

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

在案例1)中,您可以从抽象基类型访问这些方法,而无需知道确切的类型(抽象方法是虚方法)。

抽象类的要点通常是在基类上定义一些契约,然后由派生类实现(在这种情况下,重要的是要认识到接口是一种“纯抽象类”)。

嗯,不同的是,基类会知道前者,而不是后者。

换句话说,使用基类中的抽象方法,您可以在调用该抽象方法的基类中的其他方法中编写代码。

显然,如果基类没有那些方法……你不能称它们为…

抽象函数不具有任何function。 你基本上是在说,任何一个子类必须给出他们自己的这个方法的版本,但是它太普遍甚至不能尝试在父类中实现。 一个虚函数,基本上就是说看,这里的function对于子类来说可能是也可能不够好。 所以,如果它足够好,请使用此方法,如果没有,则覆盖我,并提供您自己的function……

当然,如果覆盖虚方法,则始终可以通过调用base.myVirtualMethod()来引用父方法。

好的,当你看到这样的方法时:

 A.Foo(); 

你真正拥有的(幕后)是这样的签名。

 Foo(A x); 

当你调用A.Foo()你真的在调用Foo(this)this是对A类对象的引用。

现在,有时你想拥有Foo(A|B|C|D...) ,其中Foo是一种可以采用A型,B型,C型或D型的方法。但是你不想要担心你传递的是什么类型,你只是希望它根据传入的类型做一些不同的事情。抽象方法让你这样做,这是他们唯一的目的。