什么是抽象类?

当我了解抽象类时,就说WT(H *)!!!

问题:

  1. 创建一个无法实例化的类有什么意义?
  2. 为什么有人想要这样的课?
  3. 抽象类成为必需的情况是什么?

**如果你明白我的意思*

  1. 最常用作基类或接口(某些语言有单独的interface结构,有些没有) – 它不知道实现(由子类/实现类提供)
  2. 抽象和重用
  3. 当基类不能为方法提供有意义的默认实现时(但允许子类重用实现的非抽象部分;任何字段,非抽象方法等)

例如:

 public abstract class Stream { /* lots of code, some abstract methods */ } 

什么是流本身 ? 什么的流? 一个文件流? 一个网络? 内存缓冲区? 每个都可能有不同的和不相关的读/写方式,但提供了一个通用的API。 创建一个Stream没有意义的 ,但是通过abstract类,您可以在不知道详细信息的情况下编写 Stream API 代码

 Stream s = CreateStream(...); // I don't *care* what kind of stream s.Write(new byte[] {1,2,3,4,5}); s.Close(); 

Abstract(Base)类为您提供半具体类来实现您的类层次结构。 它们允许您做几件事:

  1. 合并常见行为(与仅定义合同的接口不同)
  2. 为函数提供默认(以及可选的可覆盖)实现
  3. 为inheritance层次结构提供定义明确的分支点
  4. 控制IoC注入点

名单还在继续。

1)创建一个无法实例化的类有什么意义?

仅仅因为没有直接实例化的东西并不意味着它是有用的。 抽象类在inheritance中起着重要作用,并且在其inheritance类的类设计中非常有用。

例如,我之前使用过抽象类来定义类必须符合的基本结构。 然后我基于该抽象类定义了inheritance类,如果我错过了必需的方法或其他东西,它可以被编译器选中。

这也允许你做的是将inheritance的类关联在一起,这意味着你可以假设抽象类中定义的某些方法将存在于inheritance的类中 – 这可能很有用。

2)为什么有人想要这样的课程

通常我使用它来确保一系列inheritance的类具有某些方法等。对我来说,它对于设计一组inheritance类的结构非常有用。

3)抽象类变得必要的情况是什么?

我不认为抽象类是必要的,但在某些情况下使用它可能有用并有助于简化您正在解决的问题。

重点是指定派生类必须实现的方法,与接口相同,但也提供一些实现(接口不能执行)。 严格来说,抽象类从来都不是“必要的” – 但它们很有用。 只需在.NET或Java标准库中搜索它们,并亲自查看它们的使用方法。 你会发现有很多例子。

抽象类仅在使用inheritance时才有用。 您创建的子类必须实现与抽象类相同的接口 ,并将inheritance您在抽象类中定义的一些基本实现。

它只是隐藏来自使用它的客户端的实际实现。

  • 它提供了某些function的概念实现,但这不能直接实例化
  • 这只能从正在实现它的类中访问。
  • 因此,使用派生类的客户端将永远不会知道该function的实现,因为它已被抽象化。

现在你会问为什么我们需要这个,因为接口提供相同的机制。通过简单的记录器示例

 interface ILogger { string PrepareLog(System.Exception ex); void InitializeLogger(string Type); int WriteLog(string msg); } 

任何日志客户端实现此接口都应实现所有此function

  class EventLogger : ILogger { public override void InitializeLogger(string Type) { //Event Logger Initialize } public override int WriteLog(string msg) { //Write to event log return 1; } public override string PrepareLog(System.Exception ex) { return ex.StackTrace ; } } class FileLogger : ILogger { public override void InitializeLogger(string Type) { } public override int WriteLog(string msg) { //Write to File return 1; } public override string PrepareLog(System.Exception ex) { return ex.StackTrace ; } } class MailLogger : ILogger { public override void InitializeLogger(string Type) { } public override int WriteLog(string msg) { //Write to mail return 1; } public override string PrepareLog(System.Exception ex) { //prepare HTML Formatted msg return ex.StackTrace ; } } 

EventLogger,FileLogger和maillogger类实现了iLogger并提供了Context Specific实现。 现在我们想要隐藏PrepareLog的实际实现,这将执行从exception对象准备日志消息的常见操作。

在我们目前的实施中,我们没有选择使单一方法具体化而其他方法只是合同。

所以让我们用抽象类改变实现

 abstract class AbstractLogger:ILogger { #region ILogger Members public virtual string PrepareLog(System.Exception ex) { return ex.StackTrace; } public abstract void InitializeLogger(string Type); public abstract int WriteLog(string msg); #endregion } class EventLogger : AbstractLogger { public override void InitializeLogger(string Type) { //Event Logger Initialize } public override int WriteLog(string msg) { //Write to event log return 1; } } class FileLogger : AbstractLogger { public override void InitializeLogger(string Type) { } public override int WriteLog(string msg) { //Write to File return 1; } } class DBLogger : AbstractLogger { public override void InitializeLogger(string Type) { } public override int WriteLog(string msg) { //Write to DB return 1; } } class MailLogger : AbstractLogger { public override void InitializeLogger(string Type) { } public override int WriteLog(string msg) { //Write to mail return 1; } public override string PrepareLog(System.Exception ex) { //prepare HTML Formatted msg return ex.StackTrace ; } } 

现在我已经创建了AbstractLogger类,该类inheritance自iLogger并单独实现了PrepareLog方法,其余方法仍然是抽象的。 因此消费者将在其实现中编写特定于上下文的代码。

所以现在PrepareLog方法完全隐藏(意思是日志准备)来自cosumers初始化任何Logger。

那么为什么PrepareLog是Virtual ed ??

在某些情况下,消费者可能希望覆盖preparelog方法,Ex:MailLogger将覆盖PrepareLog并格式化HTML格式的输出以提供给邮件消息。

抽象类是一种抽象 。 它保证行为存在但不强制行为的实施方式。 如果您以后决定要这样做,这可以让您自由地更改行为的实现方式。

抽象就像键盘,显示器或手机。 所有键盘都能输入数据; 所有显示器都能够显示像素; 并且所有手机都能够拨打电话。 但是这些项目的制造商有不同的实现行为的方式。

因此,当您想要拨打电话时,您可以从几乎所有手机中进行呼叫,因为所有手机制造商都会创建符合手机常见抽象概念的手机。 如果您已经学会了如何在BlackBerry或LG上进行操作,则无需重新学习如何在三星上拨打电话。

手机是手机 ,抽象类的子类都是抽象类

抽象类是无法实例化的类。 例如,Square,Circle或Rectangle是一种形状,可以从类Shape派生。

Shape将包含Square,Circle或Rectangle共有的代码,例如计算形状的区域。 但是实例化一个Shape将是无用的,因为它是一个抽象概念,正方形,圆形和矩形是真实实体。

抽象类的要点是定义(限制)您的接口,而不描述实现。

  1. 可以通过使用派生类类型构造兼容对象来实例化抽象类。

  2. 实现一个隐藏丑陋平台特定代码的干净界面。 也是为了隐藏任何暴露的私人。 (这样你就真的被迫使用带有抽象接口的类。)

  3. 当您有两个完全不同的同一类的不同实现时,这是必要的。 想想文件,套接字和内存块。 所有这些都可以使可读数据可用 – 使用抽象类,您可以以三种不同的方式实现这三种,即使使用代码(调用站点)是以支持所有三种方式编写的。

接口和抽象类都会促进代码库中的松散耦合。 抽象类是接口和具体类之间的折衷,因为抽象类可以具有实现行为的实际方法。

通常,更喜欢接口。 如果您的inheritance树具有子类使用的常用操作,则抽象类很有用。 但即使在这里,您也可能希望声明您的抽象类实现了一个接口。 Josh Bloch称之为“抽象接口”模式。 这允许你部署甚至抽象类的不同实现,而矛盾的是它实际上并不是完全抽象的 – 只有接口才是。

好的,现在您创建了一个接口,其中包含每个实现中更改的所有方法。 在编程时,您会注意到某些代码块由接口的所有实现共享。

这些代码块应该放在抽象类中,而不是在每个实现中重复。 这样,当某些内容发生变化时,您只需在抽象类中而不是在每个实现中修复代码。

它只是抽象的,因为您希望所有inheritance类都有自己的实现。

抽象类通过能够创建一个体现概念而不是具体内容的类来实现有用的目的。 例如, 动物可以是一个类,但没有人只是动物,它是等,它们是不同种类的动物。 希望这可以帮助。 它还与inheritance和多态等概念相结合。

与接口相同,抽象类是一种契约 ,您在其中提供了适用于许多场景的一些通用(或抽象 )function,但期望实现者为每个场景提供特定和/或不同的某些function。 有人提到了Stream示例 – 非常好的例子。