我知道接口和抽象类之间的区别。现在我想知道我需要在抽象类上使用接口,反之亦然。
我提到的文章Recommendations for Abstract Classes vs. Interfaces
在那
以下是一些建议,可帮助您决定是使用接口还是抽象类来为组件提供多态性。
如果您预计会创建多个版本的组件,请创建 一个抽象的类。抽象类提供了一种简单易行的方法 版本你的组件。通过更新基类,全部继承 类会随着更改自动更新。接口,关于 另一方面,一旦创建就无法改变。如果是新版本的 界面是必需的,你必须创建一个全新的界面。
如果您创建的功能在各种不同的对象中都有用,请使用界面。抽象类应该 主要用于密切相关的对象,而 接口最适合提供通用功能 无关的课程。
如果您正在设计小巧,简洁的功能,请使用 接口。如果您正在设计大型功能单元,请使用 抽象类。
- 醇>
如果要在组件的所有实现中提供通用的实现功能,请使用抽象类。抽象类允许您部分实现您的类,而接口不包含任何成员的实现。
我不确定第3点。我是否需要将组件的所有小功能放入界面?
任何真实世界/可理解的例子都可以帮助我选择每个?
答案 0 :(得分:1)
我通常只是查看代码并尝试确定是否存在可以“使用”的常用方法,用于相关层次结构中的不同对象。即如果A类和B类继承了相同的共同祖先C,因为它们是相似的 - 它们的功能是否相同?在这种情况下,C可能是一个抽象类,其方法doSomething()只需要在C中指定(如果C是一个接口,A和B都必须提供自己的doSomething()方法实现)。
我认为这就是#3的暗示,如果你使用接口设计大型功能单元,一切都需要重新实现,这意味着很多代码。如果没有“常见”方法做类似的事情,实现太不同了,应该根本不属于同一个接口。 (但是,这种推理在很大程度上假设所使用的所有重要类都是某些适当的继承结构的一部分,但情况可能并非总是如此,例如,如果您使用第三方API。)
答案 1 :(得分:1)
想象你正在创建一个动画,你有车辆和人都应该从IMovable继承因此这里独立于类原点你应该能够初始化一个IMovable数组并调用你的界面中定义的Move方法这将让你能够当你召唤移动让人走路和车轮转向时只需一次调用方法,因为这里每个班级都有自己的行为实施Move
对于第二部分,请看一下这个链接http://dofactory.com/Patterns/PatternAbstract.aspx#_self2,因为它完全解释了为什么你应该使用抽象而不是接口,例如食肉动物有一个常见的方法吃,默认情况下可以从所有的儿童类中使用,因为食肉动物应该吃食草动物。
希望这个帮助
答案 2 :(得分:1)
接口就像合同。如果代码的任何部分应该依赖于某些方法或属性的存在,那么界面是个好主意。它还为单元测试提供了更多空间。
很多时候我定义了一个接口和实现它的抽象类。这样,您可以在不从基类派生的情况下实现接口。
至于真实的例子,例如考虑一个消息网关。 请注意,以下实现不是OOP完美的。我只是不想创建这么多的类和接口。
interface IMessageSender
{
string From { get; set; }
string To { get; set; }
string Message { get; set; }
void Send();
}
abstract class MessageSenderWithSubjectBase : IMessageSender
{
string From { get; set; }
string To { get; set; }
string Message { get; set; }
string Subject { get; set; }
abstract void Send();
}
class EmailSender : MessageSenderWithSubjectBase
{
override void Send() { // send email }
}
class SmsSender : IMessageSender
{
override void Send() { // send sms }
}
请参阅,SMSes没有主题。您也可以从抽象类派生,只是忽略主题,但这不是一个清晰的设计。更不用说在基类中有常见方法的情况下,您知道根本不需要。相反,您可以为没有主题的消息创建基类,或者只是实现接口。
当您需要发送消息时,在代码的某处,您可能会从某种工厂获得消息发送者,并且您可以依赖它能够发送消息,因为它实现了接口。你可以这样抽象。
虽然这个答案没有直接回答你的问题,但这是因为我不认为你可以像你读过的那样创建规则。给定时间和许多行代码,您最终将了解何时需要接口,抽象类或两者同时。
答案 3 :(得分:0)
回答第(3)点。
如果您正在设计小巧,简洁的功能,请使用 接口。如果您正在设计大型功能单元,请使用 抽象类。
示例可以是小功能,例如辅助函数或可重用代码块。我最近实现了一个验证provider,它有一个方法Validate
,用于逻辑相关和不相关的具体对象。
答案 4 :(得分:0)
大多数情况下,在决定是否应该使用接口或抽象类之间进行讨论时,它最终会定义如何使用它们,但不总是为什么以及何时使用?此外,您可能最终使用的其他明显的其他具体类和实用程序类也并非总是如此。实际上,在我的想法中,回答问题的正确方法是确定您正在处理的关于域或实体对象的上下文,即您的用例是什么?
从很高的层面来说,Java由可以使用方法相互通信的对象(可以在现实世界中建模对象的实体或域对象)组成。无论如何,您希望使用接口对行为进行建模,并在继承时使用抽象类。
我使用自上而下自下而上的方法。我通过查看用例并查看我将需要的类来开始寻找继承。然后我看看是否有一个superClassOrInterfaceType(因为类和接口都定义了类型,为了简单起见,我将它们组合成一个单词。希望它不会让它更加混乱)包含所有对象的域对象,如果我正在处理一个处理subtypeClassOrInterfaceTypes的用例,例如汽车,卡车,吉普车和摩托车,就像在车辆的superClassOrInterfaceType中一样。如果存在层次关系,那么我定义了superClassOrInterfaceType和subtypeClassOrInterfaceTypes。
正如我所说,我通常首先要做的是为我正在处理的对象寻找一个公共域superClassOrInterfaceType。如果是这样,我寻找subtypeClassOrInterfaceTypes之间的常见方法操作。如果没有,我会查看是否存在常见的方法实现,因为即使您可能具有superClassOrInterfaceType并且可能具有常用方法,但实现可能不支持代码重用。在这一点上,如果我有共同的方法,但没有常见的实现,我倾向于接口。但是,通过这个简单的示例,我应该有一些常见的方法,在车辆subtypeClassOrInterfaceTypes之间可以重用代码的一些常见实现。
另一方面,如果没有继承结构,那么我从下往上开始查看是否有常用方法。如果没有通用的方法,也没有常见的实现,那么我选择一个具体的类。
通常,如果存在使用常见方法和常见实现的继承以及在同一子类型中需要多个子类型实现方法,那么我使用抽象类,这很少见,但我确实使用它。如果你只是因为存在继承而使用抽象类,那么如果代码发生很大变化,你可能会遇到问题。这里的示例非常详细:Interfaces vs Abstract Classes in Java,用于电机的不同类型的域对象。其中一个需要双动力马达,需要在单个子类型中使用多个子类型实现方法。
总结一下,作为一项规则,您希望使用接口而不是Abstract类来定义行为(对象将执行的操作)。抽象类专注于实现层次结构和代码重用。
以下是一些链接,详细介绍了这一点。
The Magic behind Subtype Polymorphism