为什么要使用接口,多重继承与接口,接口的好处?

时间:2011-12-16 07:52:17

标签: java oop inheritance interface multiple-inheritance

我对此事仍然有些困惑。我到现在所发现的是

(这里已经提出了类似的问题,但我还有其他一些观点。)

  
      
  1. 接口是仅抽象方法和最终字段的集合。

  2.   
  3. Java中没有多重继承。

  4.   
  5. 接口可用于在Java中实现多重继承。

  6.   
  7. 继承的一个优点是我们可以在派生类中使用基类代码而无需再次编写它。这可能是继承最重要的事情。

  8.   

现在..

  

Q1。由于接口只有抽象方法(没有代码)所以我们怎么说如果我们实现任何接口那么它是继承?我们没有使用它的代码。

     

Q2。如果实现接口不是继承,那么如何使用接口来实现多重继承?

     

Q3。无论如何使用Interfaces有什么好处?他们没有任何代码。我们需要在我们实现它的所有类中反复编写代码。

那为什么要制作界面?

注意:我找到了一个接口有用的案例。它的一个例子就像在Runnable接口中我们有public void run()方法,我们在其中定义线程的功能,并且内置编码,该方法将作为单独的线程运行。所以我们只需要编写线程中的代码,Rest是预定义的。但是这个东西也可以用抽象类和所有东西来实现。

那么使用接口的确切好处是什么?我们使用Interfaces实现了多重继承吗?

11 个答案:

答案 0 :(得分:34)

  

Q1。由于接口只有抽象方法(没有代码)所以我们怎么说如果我们实现任何接口那么它是继承?我们没有使用它的代码。

我们做不到。接口不用于实现多重继承。他们用更安全但更弱的构造来代替它。请注意关键字implements而不是extends

  

Q2。如果实现接口不是继承,那么如何使用接口来实现多重继承?

他们不是。使用接口,单个类可以具有多个“视图”,不同的API或功能。例如。一个类可以同时是RunnableCallable,而两种方法都可以有效地做同样的事情。

  

Q3。无论如何使用Interfaces有什么好处?他们没有任何代码。我们需要在我们实现它的所有类中反复编写代码。

接口是一种多重继承,没有后者引入的问题(如Diamond problem)。

接口的用例很少:

  1. 对象实际上有两个身份:Tank 既是Vehicle又是Weapon。您可以使用Tank的实例,其中前者或后者是预期的(多态)。这在现实生活中很少出现,实际上是一个有效的例子,其中多重继承会更好(或特征)。

  2. 简单职责:游戏中Tank对象的实例也是Runnable,允许您在线程中执行它,ActionListener来响应鼠标事件。< / p>

  3. 回调接口:如果对象实现了给定的回调接口,则会通知它有关其生命周期或其他事件的信息。

  4. 标记界面:不添加任何方法,但可以通过instanceof轻松访问,以发现对象功能或愿望。 SerializableCloneable就是一个例子。

  5. 你正在寻找的是特质(就像在Scala中一样),遗憾的是在Java中不可用。

答案 1 :(得分:9)

<强> KISS

我已经搜索了几天,试图了解界面并且似乎阅读相同的通用帮助;我不是要贬低这些贡献,但我认为只是点击了灯泡,所以我很喜欢:))

我更喜欢保持简单愚蠢,因此将提供我新发现的界面视图。

我是一个随便的编码器,但我想发布我在VB.NET中编写的代码(其他语言的原理是相同的),以帮助其他人理解界面。

如果我错了,请在后续评论中告诉其他人。

<强>解释

表单上的三个按钮,单击每个按钮可以保存对接口变量(_data)的不同类引用。不同类引用到接口变量的整点是我不理解的,因为它似乎是多余的,然后它的功能随着msgbox变得明显,我只需要调用SAME方法来执行我需要的任务,在此case'GetData()',它使用当前由接口引用变量(_data)保存的类中的方法。

因此,我想获取我的数据(来自数据库,网络或文本文件),它只使用相同的方法名称;该实现背后的代码......我不在乎。

然后使用界面更改每个类代码很容易,没有任何依赖性......这是OO和封装的关键目标。

何时使用

代码类,如果您注意到用于方法的相同动词,例如'GetData()',那么它是在该类上实现接口并将该方法名称用作抽象/接口的良好候选者。

我真诚地希望这能帮助一个老将这个困难的原则。

Public Class Form1

Private _data As IData = Nothing

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    _data = New DataText()
    MsgBox(_data.GetData())
End Sub

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
    _data = New DataDB()
    MsgBox(_data.GetData())
End Sub

Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
    _data = New DataWeb()
    MsgBox(_data.GetData())
End Sub

End Class

Public Interface IData
Function GetData() As String
End Interface

Friend Class DataText : Implements IData

Friend Function GetData() As String Implements IData.GetData
    Return "DataText"
End Function

End Class

Friend Class DataDB : Implements IData

Friend Function GetData() As String Implements IData.GetData
    Return "DataDB"
End Function

End Class

Friend Class DataWeb : Implements IData

Friend Function GetData() As String Implements IData.GetData
    Return "DataWeb"
End Function

End Class

答案 2 :(得分:5)

  

Q1。由于接口只有抽象方法(没有代码)所以我们怎么说如果我们实现任何接口那么它是继承?我们没有使用它的代码。

不幸的是,在口语用法中,当一个类实现一个接口时,inheritance这个词仍然经常被使用,虽然interface implementation是一个更好的术语 - IMO,术语inheritance应该是严格的用于继承具体或抽象类。在像C ++和C#这样的语言中,相同的语法(即Subclass : SuperclassClass : Interface)用于类继承和接口实现,这可能导致滥用单词{{1带接口。 Java有inheritance类的不同语法而不是extend接口,这是一件好事。

  

Q2如果实现接口不是继承,那么如何使用接口来实现多重继承?

您可以通过组合实现多重继承的“效果” - 通过在类上实现多个接口,然后为类中所有接口所需的所有方法,属性和事件提供实现。使用具体类执行此操作的一种常见技术是通过将实现“连接”到每个内部类实现来实现外部接口的类来实现“has-a”(组合)关系。 (像C ++这样的语言确实直接支持多个具体的继承,但是会产生其他潜在的问题,比如钻石问题)。

  

Q3无论如何使用Interfaces有什么好处?他们没有任何代码。我们需要在我们实现它的所有类中反复编写代码。

接口允许现有的类(例如框架)与您的新类进行交互,而无需事先“看到”它们,因为它具有通过已知接口进行通信的能力。将接口视为合同。通过在类上实现此接口,您在合同上必须满足其所需的义务,并且一旦实现此合同,那么您的类应该能够与使用该接口的任何其他代码互换使用。

  

真实世界的例子

“现实世界”的例子是围绕特定国家的电壁式插座的立法和惯例(界面)。插入插座的每个电器需要满足当局为插座定义的规范(合同),例如,线路,中性线和地线的定位,开/关开关的位置和颜色,以及开启时通过implement提供的电压,频率和最大电流的一致性

将接口(即标准墙壁插座)分离而不仅仅是将电线焊接在一起的好处是,您可以插入(和拔下)风扇,水壶,双适配器或下一个要发明的新设备虽然这个设备在界面设计时不存在,但它已经进入了它。为什么?因为它符合接口的要求。

  

为什么要使用界面?

接口非常适合松散耦合类,并且是Bob叔叔的SOLID范例的主要内容之一,尤其是interfaceDependency Inversion Principle

简单地说,通过确保类之间的依赖关系仅在接口(抽象)上而不是在其他具体类上耦合,它允许依赖性替换为满足接口要求的任何其他类实现。

在测试中,依赖关系的存根和模拟可以用于对每个类进行单元测试,并且类可以与依赖关系进行交互。

答案 3 :(得分:5)

这是一个非常古老的问题,java-8版本增加了更多功能。接口的力量。

接口声明可以包含

  1. 方法签名
  2. 默认方法
  3. 静态方法
  4. 不变的定义。
  5. 在界面中实现的唯一方法是默认静态方法。

    界面的使用:

    1. 定义合同
    2. 使用功能链接不相关的类(例如,实现Serializable接口的类可能有也可能没有任何关系,除了实现该接口
    3. 提供可互换的实施,例如Strategy_pattern
    4. 默认方法使您能够向库的接口添加新功能,并确保二进制兼容性以及为这些接口的旧版本编写的代码
    5. 使用 static 方法在库中组织帮助器方法(可以在同一个接口中保留特定于接口的静态方法,而不是在单独的类中)
    6. 请查看此相关的SE问题以获取更好地理解概念的代码示例:

      How should I have explained the difference between an Interface and an Abstract class?

      回到你的疑问:

        

      Q1。由于接口只有抽象方法(没有代码)所以我们怎么说如果我们实现任何接口那么它是继承?我们没有使用它的代码。

           

      Q2。如果实现接口不是继承,那么如何使用接口来实现多重继承?

      界面可以包含静态默认方法的代码。这些默认方法提供向后兼容性和静态方法提供 helper / utility 函数。

      你不能在java中拥有真正的多重继承,并且接口不是获取它的方法。接口只能包含常量。所以你不能继承状态,但你可以实现行为。

      您可以将继承替换为功能 Interface提供了多种实现类的功能。

        

      Q3。无论如何使用Interfaces有什么好处?他们没有任何代码。我们需要在我们实现它的所有类中反复编写代码。

      请参阅我的回答中的“使用界面”部分。

答案 4 :(得分:3)

继承是指一个类派生自另一个类(可以是抽象的)或接口。面向对象(继承)的最强点不是代码的重用(有很多方法可以做到),而是多态性。

多态性是指您拥有使用接口的代码,它的实例对象可以是从该接口派生的任何类。例如,我可以有这样的方法: public void Pet(IAnimal animal)和此方法将获得一个对象,该对象是从IAnimal继承的Dog或Cat的实例。或者我可以有这样的代码: 动物 然后我可以调用这个接口的方法: dog.Eat(),狗或猫可以用不同的方式实现。

接口的主要优点是你可以从其中一些继承,但是如果你只需要从一个继承,你也可以使用一个抽象类。这篇文章解释了抽象类和接口之间的差异: http://www.codeproject.com/KB/cs/abstractsvsinterfaces.aspx

答案 5 :(得分:2)

两种方法都有效(接口和多重继承)。

快速实用简答

如果您有多年使用多重继承的经验,只有方法定义,而且根本没有代码,那么接口会更好。

补充问题可能是:“如何以及为什么要将代码从抽象类迁移到接口”。

如果你没有在你的应用程序中使用很多抽象类,或者你没有多少经验,你可能更喜欢跳过接口。

不要急于使用接口。

长期无聊的回答

接口非常相似,甚至等同于抽象类。

如果你的代码有很多抽象类,那么你就开始考虑接口了。

以下带抽象类的代码:

MyStreamsClasses.java

/* File name : MyStreamsClasses.java */
import java.lang.*;
// Any number of import statements

public abstract class InputStream {
  public void ReadObject(Object MyObject);
}

public abstract class OutputStream {
  public void WriteObject(Object MyObject);
}

public abstract class InputOutputStream 
    imnplements InputStream, OutputStream {
  public void DoSomethingElse();
}

可替换为:

MyStreamsInterfaces.java

/* File name : MyStreamsInterfaces.java */
import java.lang.*;
// Any number of import statements

public interface InputStream {
  public void ReadObject(Object MyObject);
}

public interface OutputStream {
  public void WriteObject(Object MyObject);
}

public interface InputOutputStream 
    extends InputStream, OutputStream {
  public void DoSomethingElse();
}

干杯。

答案 6 :(得分:1)

老问题。令我感到惊讶的是,没有人引用规范来源:James Gosling的 Java:概述设计模式:可重复使用的面向对象软件的元素或Joshua Bloch的 Effective Java (以及其他来源)。

我将从引用开始:

  

接口只是对象响应的一组方法的规范。它不包含任何实例变量或实现。接口可以是多重继承的(与类不同),它们可以比通常的刚性类更灵活地使用   继承结构。 (Gosling,第8页)

现在,让我们逐一考虑您的假设和问题(我将自愿忽略Java 8的功能)。

假设

接口是仅抽象方法和最终字段的集合。

您是否在Java界面中看到关键字abstract?不。那么你不应该将接口视为抽象方法的集合。也许你被C ++所谓的接口误导,这些接口只有纯虚方法。 C ++在设计上没有(也不需要)接口,因为它具有多重继承。

正如Gosling所解释的那样,您应该将接口视为&#34;一组对象响应的方法&#34;。我希望将界面和相关文档视为服务合同。它描述了您可以从实现该接口的对象中获得的内容。文档应指定前置和后置条件(例如,参数不应为空,输出始终为正,...)和不变量(不修改对象内部状态的方法)。我认为,这份合同是OOP的核心。

Java中没有多重继承。

确实

  

JAVA省略了许多很少使用,知之甚少,令人困惑的C ++功能,这些功能在我们的经验中带来了更多的悲伤而不是利益。这主要包括运算符重载(尽管它确实有方法重载),多重继承和广泛的自动强制。 (Gosling,第2页)

无需添加任何内容。

接口可用于在Java中实现多重继承。

不,simlpy,因为Java中没有多重继承。见上文。

继承的一个优点是我们可以在派生类中使用基类代码而无需再次编写它。可能这是继承在那里最重要的事情。

这被称为&#34;实现继承&#34;。正如您所写,它是重用代码的便捷方式。

但它有一个重要的对应物:

  

父类通常至少定义其子类的一部分&#39;物理代表。因为继承将子类暴露给其父实现的细节,所以它经常说&#34;继承打破了封装和#34; [Sny86]。子类的实现与其父类的实现密切相关,父实现的任何更改都将强制子类发生更改。 (GOF,1.6)

(布洛赫第16项中有类似的引用。)

实际上,继承还有另一个目的:

  

类继承结合了接口继承和实现继承。接口继承定义了一个新的接口   或更多现有接口。实现继承根据一个或多个现有实现定义新实现。 (GOF,附录A)

两者都在Java中使用关键字extends。您可能具有类和接口层次结构的层次结构。第一个分享实施,第二个分担义务。

问题

Q1。由于接口只有抽象方法(没有代码)所以我们怎么说如果我们实现任何接口那么它是继承?我们没有使用它的代码。**

接口的实现不是继承。它的实施。因此关键字implements

Q2。如果实现接口不是继承,那么如何使用接口来实现多重继承?**

Java中没有多重继承。见上文。

Q3。无论如何使用Interfaces有什么好处?他们没有任何代码。我们需要在我们实现它的所有类中一次又一次地编写代码。那么为什么要创建接口?/使用接口的确切好处是什么?我们使用Interfaces实现了多重继承吗?

最重要的问题是:你为什么要进行多重继承?我可以想到两个答案:1。给一个对象提供多种类型; 2.重用代码。

将mutliple类型赋予对象

在OOP中,一个对象可能具有不同类型。例如,在Java中,ArrayList<E>具有以下类型:SerializableCloneableIterable<E>Collection<E>List<E>,{{1} },RandomAccessAbstractList<E>AbstractCollection<E>(我希望我没有忘记任何人)。如果对象具有不同类型,则各种消费者将能够使用它而不了解其特性。我需要一个Object你给我一个Iterable<E>?没关系。但是,如果我现在需要一个ArrayList<E>并且你给我一个List<E>,那也可以。等

如何在OOP中键入对象?您以ArrayList<E>界面为例,此示例非常适合说明此问题的答案。我引用官方Java文档:

  

此外,Runnable提供了一个类活动而不是继承Thread的方法。

重点:继承是输入对象的便捷方式。您想创建一个帖子吗?让我们对Runnable类进行子类化。您希望对象具有不同的类型,让我们使用多重继承。哎呀。它并不存在于Java中。 (在C ++中,如果您希望对象具有不同的类型,则可以采用多重继承。)

如何将mutliple类型赋予对象呢?在Java中,您可以直接键入对象 。这是您在课程Thread implements界面时所执行的操作。如果你是继承的粉丝,为什么要使用Runnable?也许是因为你的班级已经是另一个班级的子类,让我们说Runnable。现在,您的班级有两种类型:AA

使用多个接口,您可以为对象提供多种类型。您只需要创建一个Runnable多个接口的类。只要你遵守合同,就没问题。

重复使用代码

这是一个难题;我已经引用GOF来打破封装。其他答案提到钻石问题。您还可以考虑单一责任原则:

  

一个班级应该只有一个改变的理由。 (Robert C. Martin,敏捷软件开发,原理,模式和实践)

除了自己的职责之外,拥有一个父类可以给一个班级改变的理由:

  

超类的实现可能会在不同版本之间发生变化,如果确实如此,子类可能会中断,即使其代码未被触及。因此,子类必须与其超类(Bloch,第16项)一起发展。

我会添加一个更平淡的问题:当我尝试在类中找到方法的源代码时,我总是有一种奇怪的感觉,而我无法找到它。然后我记得:它必须在父类的某个地方定义。或者在祖父母班上。或者甚至更高。在这种情况下,一个好的IDE是一个有价值的资产,但在我看来,它仍然是一些神奇的东西。没有类似于接口的层次结构,因为javadoc是我唯一需要的东西:IDE中的一个键盘快捷键,我得到它。

继承howewer有优势:

  

在包中使用继承是安全的,其中子类和超类实现受同一程序员的控制。在扩展专门为扩展而设计和记录的类时,使用继承也是安全的(第17项:继承的设计和文档,否则禁止它)。 (布洛赫,第16项)

一个类&#34的示​​例;专门为扩展而设计和记录的#34;在Java中是implements

但布洛赫和GOF坚持这样做:&#34;赞成作品而不是继承&#34;:

  

委托是一种使组合像继承一样重用的方法[Lie86,JZ91]。在委托中,处理请求涉及两个对象:接收对象将操作委托给其委托。这类似于将子请求延迟到父类的子类。 (GOF第32页)

如果您使用合成,则不必反复编写相同的代码。您只需创建一个处理重复的类,然后将此类的实例传递给实现接口的类。这是重用代码的一种非常简单的方法。这有助于您遵循单一责任原则并使代码更易于测试。 Rust和Go没有继承(他们也没有课程),但我不认为代码比其他OOP语言更冗余。

此外,如果您使用合成,您会发现自然使用接口为您的代码提供所需的结构和灵活性(请参阅有关接口用例的其他答案)。

注意:您可以与Java 8接口共享代码

最后,最后一句话:

  

在令人难忘的Q&amp; A会话期间,有人问他[James Gosling]:&#34;如果你能再次做Java,你会改变什么?&#34; &#34;我要离开课程&#34; (在网上的任何地方,不知道这是否属实)

答案 7 :(得分:0)

进行接口,以便类在接口内实现功能并按照该接口行事。

答案 8 :(得分:0)

<强> Q1。由于接口只有抽象方法(没有代码)所以我们怎么说如果我们实现一个接口那么它是继承?我们没有使用其代码。

这不是平等的继承。它只是类似的。让我解释一下:

VolvoV3 extends VolvoV2, and VolvoV2 extends    Volvo (Class)
VolvoV3 extends VolvoV2, and VolvoV2 implements Volvo (Interface)

line1: Volvo v = new VolvoV2(); 
line2: Volvo v = new VolvoV3(); 

如果只看到line1和line2,则可以推断出VolvoV2和VolvoV3的类型相同。你无法推断出沃尔沃是超类还是沃尔沃是一个界面。

<强> Q2。如果实现接口不是继承,那么如何使用接口来实现多重继承?

现在使用接口:

VolvoXC90 implements XCModel and Volvo (Interface)
VolvoXC95 implements XCModel and Volvo (Interface)

line1: Volvo   a = new VolvoXC90();
line2: Volvo   a = new VolvoXC95();
line3: XCModel a = new VolvoXC95();

如果只看到line1和line2,则可以推断出VolvoXC90和VolvoXC95具有相同的类型(Volvo)。你无法推断沃尔沃是一个超类或沃尔沃是一个界面。

如果你只看到第2行和第3行,你可以推断出Volvo95在Java中实现了两种类型,XCModel和Volvo,你知道至少有一种类型必须是一个接口。例如,如果这段代码是用C ++编写的,那么它们可能都是类。因此,多重遗产。

<强> Q3。无论如何,使用Interfaces有什么好处?他们没有任何代码。我们需要在我们实现它的所有类中反复编写代码。

想象一个系统,您可以在其他200个类中使用VolvoXC90类。

VolvoXC90 v = new VolvoXC90();

如果您需要改进系统以启动VolvoXC95,则必须更改200个其他类。

现在,想象一下您在10,000,000个课程中使用沃尔沃界面的系统。

// Create VolvoXC90 but now we need to create VolvoXC95
Volvo v = new VolvoFactory().newCurrentVolvoModel(); 

现在,如果你需要改进你的系统以创建VolvoXC95模型,你必须只改变一个类,即工厂。

这是一个常识问题。如果您的系统只由几个类组成并且几乎没有更新,则使用各处的接口会适得其反。对于大型系统,它可以为您节省很多痛苦并避免采用接口的风险。

我建议您阅读有关S.O.L.I.D原则的更多信息,并阅读“有效Java”一书。它拥有经验丰富的软件工程师的优秀经验教训。

答案 9 :(得分:0)

所以。这里有很多很好的答案,详细解释了什么是接口。但是,这只是它使用的一个例子,就像几年前我最好的一位同事向我解释的那样,这与我过去几年在大学里学到的东西混杂在一起。

接口是一种“合同”。它公开了一些可用的方法,字段等。它不显示任何实现细节,仅显示返回的内容和使用的参数。这是第三个问题的答案,我认为这是现代OOP的最大优势之一:

  

“添加代码,而不是修改代码” -AAU的Magnus Madsen

至少他是这样称呼的,他可能会从其他地方得到它。下面的示例代码是用C#编写的,但是显示的所有内容几乎都可以用Java相同的方式完成。

我们看到的是一个名为SampleApp的类,它具有单个字段IOContext。 IOContext是一个接口。 SampleApp并不关心如何保存数据,只需要在其“ doSomething()”方法中这样做即可。

我们可以想象,在开发过程的开始,保存数据可能比保存数据的方式更为重要,因此,开发人员选择简单地编写FileContext类。但是后来,无论出于何种原因,他都需要支持JSON。因此,他编写了JSONFileContext类,该类继承了FileContext。这意味着它实际上是一个具有FileContext功能的IOContext,保存了FileContexts SaveData和LoadData的替换,它仍然使用其“写入/读取”方法。

与编写类并让其仅继承IOContext相比,实现JSON类的工作量很小。

SampleApp的字段本来可以是'FileContext'类型,但是那样一来,它将仅限于仅使用该类的子级。通过创建接口,我们甚至可以执行SQLiteContext实现,并将其写入数据库,SampleApp将永远不会知道或不在乎,而当我们编写sql lite类时,我们只需要对代码进行一次更改:{{1} }改为new JSONFileContext();

我们仍然有旧的实现,如果需要,可以切换回那些实现。我们什么都没破坏,对代码的所有更改只有半行,可以在眨眼之间更改。

所以:代码是加法的,不是修改法。

new SQLiteContext();

答案 10 :(得分:-1)

接口

接口是定义如何与对象交互的契约。它们可用于表达内部构件如何与对象进行交互。在依赖性反转之后,您的公共API将使用接口表示所有参数。你不关心它是如何完成你需要做的,只是它完全符合你的需要。

示例:您可能只需要Vehicle来运送货物,您不必关心特定的运输方式。

继承

继承是特定实现的扩展。该实现可能满足也可能不满足特定接口。只有在关心如何实现时,才应该期待特定实现的祖先。

示例:您可能需要Plane实施车辆以便快速运输。

的组合物

组合可以用作继承的替代方法。它不是扩展基类的类,而是使用实现主类责任的较小部分的对象来创建。合成用于facade patterndecorator pattern

示例:您可以创建一个DuckBoatDUKW)类来实现LandVehicleWaterVehicle,这两个类都实现VehicleTruckBoat实现组成。

的答案

  

Q1。由于接口只有抽象方法(没有代码)所以我们怎么说如果我们实现任何接口那么它是继承?我们没有使用它的代码。

接口不是继承。实现接口表示您希望类以接口定义的方式运行。继承是指您拥有共同的祖先,并且您获得与祖先相同的行为(inherit),因此您无需定义它。

  

Q2。如果实现接口不是继承,那么如何使用接口来实现多重继承?

接口无法实现多重继承。他们表示一个班级可能适合担任多个角色。

  

Q3。无论如何使用Interfaces有什么好处?他们没有任何代码。我们需要在我们实现它的所有类中反复编写代码。

界面的一个主要好处是提供关注点分离:

  • 你可以编写一个与另一个类做某事的类,而不用考虑如何实现该类。
  • 任何未来的开发都可以与您的实现兼容,而无需扩展特定的基类。

本着DRY的精神,你可以编写一个满足界面的实现,并在你利用组合时仍然尊重open/closed principal进行更改。