我对使用抽象类或接口实现或扩展的原因感到困惑。接口不包含任何代码,抽象方法也是如此。那我们为什么要用它们呢。为什么我们不直接创建方法并在我们的类中定义它们而不是使用接口或抽象类。它们不包含任何类型的代码,我们需要在我们的类中扩展它们之后定义它们。为什么我们不在我们自己的类中定义这些方法而是扩展接口然后定义它们。我在stackoverflow中发现了几次这样的问题但是无法理解答案。任何人都可以用一些简单的方式解释它
答案 0 :(得分:3)
抽象和接口的强大之处在于您可以分离职责并编写模块化代码:您(或其他人)代码的一部分可能只关心您拥有Animal
并提供交易设施与动物,无需知道他们如何移动或喂食。代码的不同部分可能只关心定义大量具体动物,例如Dog
s,Bird
等,以及它们实际实施的所有细节所有的功能。
通过使具体类(Dog,Bird,...)扩展一个通用的抽象接口(Animal),您可以在为其编写的库中使用任何现在和将来的具体类抽象接口 - 您不需要要求库作者更改库以容纳新动物,并且库作者不需要知道如何具体实现这些功能。
例如,如果您有两个单一算法FeedBreakfast
和FeedDinner
,则需要成员函数Animal::gobble()
,然后在没有继承的情况下,您需要实现每个算法对于每只动物 - 即你最终得到M * N
代码!通过使用通用的抽象接口,您可以将其减少为M + N
- M
算法和N
具体类,并且双方都不需要知道另一方 - 他们只需要知道界面。
答案 1 :(得分:1)
静态类型语言需要使用此方法来启用多态。也就是说,您可以根据抽象基类编写代码。然后,您可以“插入”任何子类作为扩展。这称为Liskov Substitution principle或Open/Closed principle。从技术上讲,这称为dynamic binding。也就是说,根据子类,在运行时选择要调用的方法。
对于动态类型语言,情况完全不同。我不知道PHP是否是动态类型的(我怀疑它是),但是在Ruby或Javascript中,您可以根据符合特定接口的任何对象进行编程。也就是说,如果您的代码期望具有名为Print的方法的对象可以替换为也具有Print方法的任何其他对象,而不是从公共基类派生。该方法将在运行时查找,这就是为什么这些语言被称为“dynamic”。
希望这有帮助!
答案 2 :(得分:1)
如果要建立protocol,请使用抽象类或接口。
听起来很简单,但它是一个非常强大的概念。如果你被迫遵守规则,那么你就无法打破它们。如果您不能违反规则,则遵守协议。因此,实现您的接口的所有类本身应该彼此兼容。当然,人类之间也有例外,他们能够通过创建代码来打破这些规则,甚至解释器在必须解析时也会哭泣,但这有点像一个异端:)
答案 3 :(得分:1)
对于界面,假设您有一个名为“Message”的类。这实现了名为SendMessage的接口,该接口的方法定义为Send。
如果您随后创建了两个“Message”子类。一个可以是“电子邮件”,一个可以是“InstantMessage”。
现在这两个方法都有Send(),它在SendMessage接口中定义,并且是空白的。现在,您可以使用不同的方式定义Send()方法的功能。但是,因为我们知道类Email,而InstantMessage使用接口SendMessage,我们知道它们都有方法Send();
所以你可以调用Email.Send()和InstantMessage.Send(),但是做两件事。接口定义了几个对象可用的方法,但具有相同的方法名称。
答案 4 :(得分:1)
抽象类/接口主要是设计时考虑因素。通过将方法定义为抽象,因此将类定义为抽象类......我们确保通过派生类来确保这些方法的实现。如果他们不实施它们,它们也会变得抽象。
接口提供了将必须实现方法分发到不同类别的奢侈,因此可以实现所需的接口数量。
答案 5 :(得分:1)
抽象类保证不能实例化,这是因为它是一种泛化。例如, 在一个游戏中,存在一个类玩家,但也存在类防御者和前锋。类播放器是两个类的父类。不是练习创建一个对象玩家,因为一个团队需要一个特定的玩家。
接口与多态性有关。每个班级,根据其行为使用方法。
我希望这可以帮到你
答案 6 :(得分:1)
抽象类背后的想法是,您可以定义一组类似类的一些常用功能,但将其他详细信息留给实现(扩展)类。在某种程度上它们类似于接口,除了你可以实际实现抽象类中的一些函数。
但有什么意思,我听到你问?好吧,你只需要编写一次公共代码,尽管你也可以在具体的(非抽象的)基类中执行此操作。但是你也可能不希望其他程序员实例化基类,所以这就是抽象类的真正力量所在。
让我举一个例子来帮助说明我的观点。想象一下,你正在编写一个程序来对动物园里的所有动物进行分类。动物可分为某些类型,鸟类,爬行动物,哺乳动物,昆虫,节肢动物,鱼类等,然后分类为狗,猫,鹦鹉或袋鼠等物种。基类Animal可以为所有这些提供一些常用功能。它可能有一个名为eat()的函数,所有动物都以类似的方式进行操作,因此写出函数来描述动物进食的过程。它可能包含另一个函数,walk(),但这个是抽象的,因为不同的动物会以不同的方式实现它。 Animal类的所有子类都需要实现此方法。
这方面的主要好处是,您可以在代码中的某个位置调用以Animal作为参数的函数。您知道可以在此参数上调用eat()和walk()函数,因为所有动物都可以进食和行走。这称为多态,是面向对象编程的一个重要特征。
我希望这对你有所帮助。如果您仍然看不到抽象类的价值,请随时讨论或提出进一步的问题。