可能重复:
Interface vs Base class
When should I choose inheritance over an interface when designing C# class libraries?
所以我正在用C#编写我的第一个真正的程序。该计划将从四个不同的网站获取数据。我的计划是让一个父类看起来像这样:
class Scraper
{
string scrapeDate(url);
string scrapeTime(url);
//&c.
}
然后我会有四个继承它的类。
另一种选择是使Scraper
成为一个接口,并有四个实现它的类。
这些方法有何不同?
答案 0 :(得分:45)
类继承表示“is-a”关系,例如Tank
是Vehicle
。如果您的情况至少不符合此要求,请选择继承继承。
如果建议的基类没有为您的方法提供默认实现,那么这将是选择接口而不是继承的另一个原因。
在C#中,您只能从一个类继承,但只能从多个接口继承。这是选择接口而不是继承的另一个原因。
明白了吗?
答案 1 :(得分:10)
在我看来,继承是更好的方法。在基类中实现通用功能有助于确保底层实现是一致的,而实现接口只能保证接口的一致性。尽可能继承是OOP三脚架的一条腿,并限制代码重复。
当我拥有不能或不应该具有公共基类的对象时,我使用接口,但需要提供类似的功能。实现公共接口的类可能(并且可能确实)公开其他功能,可以实现多个接口等。
例如:在一个应用程序中,我的数据访问层是围绕“提供者”类构建的,这些类将业务对象和数据库代理对象与数据库隔离开来。在一个实例中,我有一个与SQL Server数据库交互的提供程序,另一个用于与Oracle CRM On Demand进行通信(又名,为什么是上帝为什么)。两者都实现了一个不可知的接口,这样客户端代码就不关心它正在处理哪个数据存储,也不关心使用它们的怪癖。
Oracle提供程序通过Web服务集合与托管服务器通信,管理连接会话,批处理请求等.SQL提供程序使用一组存储过程。虽然两个接口都接受相同的数据类,但Oracle提供程序会转换数据以匹配其深奥(轻描淡写)架构。通过这种实现,我可以轻松添加提供程序以使用XML数据存储,不同的RDBMS或存根/模拟单元测试。
在这种情况下,对于这些东西来说,拥有一个共同的基类没有多大意义,在少数情况下,这是不可能的。
答案 2 :(得分:7)
老实说,两者兼顾。
public interface IScraper
{
string ScrapeDate(string url);
}
public abstract class Scraper : IScraper
{
public string ScrapeDate(string url)
{
// default implementation
}
}
无论哪种方式都有优势,但如果不了解您的要求,很难量化。但是,你没有理由不能同时做到这两点。为您的类提供接口使其也可以用于测试目的。
要考虑的其他事情;如果每个派生类的功能足够相似,那么简单地使用一个将参数带到构造函数的类可能更容易。
答案 3 :(得分:3)
接口仅包含方法,委托或事件的签名。方法的实现是在实现接口的类中完成的。
一个类可以实现多个接口。
一个类只能有一个直接基类。
答案 4 :(得分:1)
主要差异:
在您的情况下,您的所有scraper类可能都需要一些共同的功能,因此将它们全部继承自公共基类是有意义的
答案 5 :(得分:1)
参考Abstract Class versus Interface。
有一些相似之处 界面和界面之间的差异 抽象类:
一个类可以实现几个 接口。
一个类可以只继承一个抽象 类。界面无法提供任何代码, 只是签名。
抽象类可以提供 完整的,默认的代码和/或只是 必须覆盖的细节。接口无法访问 子函数的修饰符, 属性等一切都是假定的 作为公众 抽象类可以包含访问权限 子函数的修饰符, 特性
接口用于定义 一个班级的外围能力。在 人和车都可以 继承自IMovable接口 抽象类定义核心 一个班级的身份,它就在那里 用于相同类型的对象。
如果各种实现仅共享 方法签名然后它是更好的 使用接口。
各种各样 实现是相同的 并使用共同的行为或状态 然后抽象类更好用。如果我们向接口添加新方法 然后我们要追查所有的 接口的实现和 定义新的实现 方法。
如果我们添加一个新的方法 抽象类然后我们有选择 提供默认实现 因此所有现有的代码 可能会正常工作。接口中无法定义任何字段 抽象类可以有字段和 约束定义
答案 6 :(得分:1)
您在这里看到的内容最适合作为界面。如果你想要包含一些你希望包含的常见逻辑或一些你希望包含的常见数据成员,那么你将使用一个基类并继承它。你正在做的是要求每个孩子实现一套最小的逻辑。
答案 7 :(得分:1)
接口允许定义常见行为的结构。
如果可以提取一个或多个特定行为的常见实现,则继承很有用。
基本上如果几个类以相同的方式删除日期,将scrapeDate放在基类中是有意义的;否则只使用一个接口,并在实现您的接口的每个类中定义特定的scrapeDate。
答案 8 :(得分:0)
如果你有共同的功能,你应该使用继承 - 然后在所有子类中都可以使用该功能,并且每个子类都可以扩展或覆盖父类代码。
如果您有类消耗的东西,您可以使用接口来确保所有类实现相同的方法和属性,但不一定具有相同的功能。