C#中的inheritance与接口

可能重复:
接口与基类
在设计C#类库时,何时应该在接口上选择inheritance?

所以我正在用C#编写我的第一个真正的程序。 该计划将从四个不同的网站获取数据。 我的计划是让一个父类看起来像这样:

class Scraper { string scrapeDate(url); string scrapeTime(url); //&c. } 

然后我会有四个inheritance它的类。

另一种选择是使Scraper成为一个接口,并有四个实现它的类。

这些方法有什么区别?

类inheritance表示“is-a”关系,例如, TankVehicle 。 如果您的情况至少不满足此要求,请选择inheritanceinheritance。

如果建议的基类不为您的方法提供默认实现,那么这将是选择接口而不是inheritance的另一个原因。

在C#中,您只能从一个类inheritance,但只能从多个接口inheritance。 这是选择接口而不是inheritance的另一个原因。

明白了吗?

在我看来,inheritance是在可能的情况下更好的方法。 在基类中实现通用function有助于确保底层实现是一致的,而实现接口只能保证接口的一致性。 尽可能inheritance是OOP三脚架的一条腿,并限制代码重复。

当我拥有不能或不应该具有公共基类的对象时,我使用接口,但需要提供类似的function。 实现公共接口的类可能(并且可能确实)公开其他function,可以实现多个接口等。

例如:在一个应用程序中,我的数据访问层是围绕“提供者”类构建的,这些类将业务对象和数据库代理对象与数据库隔离开来。 在一个实例中,我有一个与SQL Server数据库交互的提供程序,另一个用于与Oracle CRM On Demand(又名为什么上帝为什么)进行通信。 两者都实现了一个不可知的接口,因此客户端代码不关心它正在处理哪个数据存储,或者处理每个数据存储的怪癖。

Oracle提供程序通过Web服务集合与托管服务器通信,管理连接会话,批处理请求等.SQL提供程序使用一组存储过程。 虽然两个接口都接受相同的数据类,但Oracle提供程序会转换数据以匹配其深奥(轻描淡写)架构。 通过这种实现,我可以轻松添加提供程序以使用XML数据存储,不同的RDBMS或存根/模拟unit testing。

在这种情况下,对于这些东西来说,拥有一个共同的基类并没有多大意义,在少数情况下,这是不可能的。

老实说,两者兼顾。

 public interface IScraper { string ScrapeDate(string url); } public abstract class Scraper : IScraper { public string ScrapeDate(string url) { // default implementation } } 

无论哪种方式都有优势,但如果不了解您的要求,很难量化。 但是,没有理由你不能同时做到这两点。 为您的类提供接口使其也可用于测试目的。

还有其他要考虑的事情; 如果每个派生类的function足够相似,那么简单地使用一个将参数带入构造函数的类可能会更容易。

接口仅包含方法,委托或事件的签名。 方法的实现在实现接口的类中完成。

一个类可以实现多个接口。

一个类只能有一个直接基类。

主要差异:

  • 接口根本没有实现,而抽象基类可以实现通用function
  • 一个类只能从一个基类inheritance,但它可以实现多个接口

在您的情况下,您的所有scraper类可能都需要一些共同的function,因此将它们全部从公共基类inheritance是有意义的。

你在这里看到的最好是作为一个界面。 如果你想要包含一些你希望包含的常见逻辑或一些你希望包含的常见数据成员,那么你将使用一个基类并inheritance它。 你正在做的是要求每个孩子实现一套最小的逻辑。

接口允许定义常见行为的结构。

如果可以提取一个或多个特定行为的常见实现,则inheritance很有用。

基本上如果几个类以相同的方式删除日期,将scrapeDate放在基类中是有意义的; 否则只使用一个接口,并在实现您的接口的每个类中定义特定的scrapeDate。

参考抽象类与接口 。

接口和抽象类之间有一些相似之处和不同之处:

一个类可以实现几个接口。
一个类可以只inheritance一个抽象类。

接口不能提供任何代码,只能提供签名。
抽象类可以提供完整的默认代码和/或只需要覆盖的详细信息。

接口不能具有子,函数,属性等的访问修饰符,所有内容都被认为是公共的
抽象类可以包含subs,functions,properties的访问修饰符

接口用于定义类的外围function。 换句话说,Human和Vehicle都可以从IMovable接口inheritance。
抽象类定义类的核心标识,并在那里用于相同类型的对象。

如果各种实现仅共享方法签名,那么最好使用接口。
如果各种实现具有相同类型并使用常见行为或状态,则最好使用抽象类。

如果我们向接口添加一个新方法,那么我们必须跟踪接口的所有实现并定义新方法的实现。
如果我们向抽象类添加一个新方法,那么我们可以选择提供默认实现,因此所有现有代码都可以正常工作。

接口中无法定义任何字段
抽象类可以定义字段和约束

如果您具有通用function,则应使用inheritance – 该function将在所有子类中可用,并且每个子类都可以扩展或覆盖父类代码。

如果您有类消耗的东西,您将使用接口来确保所有类实现相同的方法和属性,但不一定具有相同的function。