题
这是有些后续问题至此 的问题.
假设我有一个继承树如下:
Car -> Ford -> Mustang -> MustangGT
是有益的接口定义 每 这些课程?例如:
ICar -> IFord -> IMustang -> IMustangGT
我可以看到,也许其他类(喜欢 Chevy
)想要实现 Icar
或 IFord
甚至可能 IMustang
, 但可能不是 IMustangGT
因为它是如此具体。是的接口多余的,在这种情况下?
此外,我将认为任何一类就要实现 IFord
肯定会想使用其一个继承通过继承 Ford
所以不要重复代码。如果这是一个给定,什么是有益的也行 IFord
?
解决方案
根据我的经验,当你有几个类需要响应相同的方法或方法时,最好使用接口,以便它们可以被其他代码互换使用,这些代码将针对这些类的通用接口编写。接口的最佳用途是协议很重要,但每个类的底层逻辑可能不同。如果您原本会复制逻辑,请考虑使用抽象类或标准类继承。
在回答问题的第一部分时,我建议不要为每个类创建一个界面。这会不必要地混乱你的类结构。如果您发现需要界面,可以随时添加。希望这有帮助!
亚当
其他提示
我同意 adamalex的回复,应该由应该响应的类共享接口某些方法。
如果类具有相似的功能,但在祖先关系中没有直接相关,那么接口将是将该功能添加到类而不在两者之间复制功能的好方法。 (或者有多个实现只有细微差别。)
虽然我们正在使用汽车类比,一个具体的例子。假设我们有以下类:
Car -> Ford -> Escape -> EscapeHybrid
Car -> Toyota -> Corolla -> CorollaHybrid
汽车有 wheels
,可以 Drive()
和 Steer()
。所以这些方法应该存在于 Car
类中。 (可能 Car
类将是一个抽象类。)
沿着这条线走下去,我们区分了 Ford
和 Toyota
(可能是因为车上标志类型的差异,也可能是一个抽象类。 )
然后,最后我们有一个 Escape
和 Corolla
类,它们是完全实现为汽车的类。
现在,我们如何制作 Hybrid 车辆?
我们可以有一个 Escape
的子类,它是 EscapeHybrid
,它添加了 FordsHybridDrive()
方法,以及 Corolla的子类
CorollaHybrid
与 ToyotasHybridDrive()
方法。这些方法基本上都是做同样的事情,但我们有不同的方法。 Yuck。好像我们可以做得更好。
假设混合具有 HybridDrive()
方法。由于我们不想最终拥有两种不同类型的混合(在完美的世界中),因此我们可以创建一个 IHybrid
接口,它具有 HybridDrive()
方法
所以,如果我们要制作 EscapeHybrid
或 CorollaHybrid
类,我们所要做的就是实现<代码> IHybrid 界面。
对于一个真实世界的例子,我们来看看Java。可以将对象与另一个对象进行比较的类实现 Comparable
接口。顾名思义,接口应该是可比较的类,因此名称为“Comparable”。
感兴趣的是汽车示例用于 Interfaces 课程中 Java教程。
类继承描述对象是 (例如:它的身份)。这很好,但是大多数情况下对象 是什么,远不如对象那么重要。这就是接口的用武之地。
界面应描述对象做什么),或者它的作用。通过这个我的意思是它的行为,以及在给定行为的情况下有意义的操作集。
因此,良好的接口名称通常应为 IDriveable
, IHasWheels
等形式。有时,描述此行为的最佳方式是引用一个众所周知的其他对象,因此您可以说“行为就像其中一个”。 (例如: IList
)但恕我直言,这种命名形式属于少数。
鉴于逻辑,接口继承有意义的场景与对象继承有意义的场景完全不同 - 通常这些场景与彼此都是。
希望能帮助您思考实际需要的接口: - )
我只说为你需要引用的东西制作一个界面。您可能还有其他一些需要了解汽车的类别或功能,但是有多少东西需要了解福特?
不要构建你不需要的东西。如果事实证明你需要接口,那么返回构建它们是一件很小的努力。
另外,在迂腐的一面,我希望你实际上并没有构建看起来像这种层次结构的东西。这不是继承应该用于什么。
只有在需要该级别的功能时才创建它。
重新分解代码始终处于正在进行的过程中。
有些工具可以让您在必要时提取界面。 例如。 http://geekswithblogs.net/ JaySmith /存档/ 2008/2月27日/重构视觉工作室提取物-interface.aspx
制作ICar和其余所有(Make = Ford,Model = Mustang和stuff)作为实现接口的类的成员。
你可能想拥有你的福特课程,例如GM课程,如果你不想沿着检查 Make == Whatever
的路线去实现ICar以便使用多态,那就是符合你的风格。
无论如何 - 在我看来,这些是汽车的属性,而不是相反 - 你只需要一个界面,因为方法很常见:刹车,加速等等。
福特可以做其他车不能做的事吗?我不这么认为。
我会创建前两个级别,ICar和IFord,然后单独留下第二级,直到我需要第二级接口。
仔细考虑您的对象如何在您的问题域中相互交互,并考虑您是否需要具有多个特定抽象概念的实现。使用接口提供围绕其他对象与之交互的概念的契约。
在您的示例中,我建议福特可能是制造商,Mustang是制造商福特使用的ModelName值,因此您可能会更喜欢:
IVehichle - &gt; CarImpl,MotorbikeImpl - 有一个制造商有很多ModelNames
在这回答有关 差之间的接口和类, 我的解释是:
- 接口暴露了什么概念 是 (中期的"是什么 是"有效的,在编制时间),和被用于 值 (MyInterface x=...)
- 类暴露了什么概念 做 (实际上是在运行时执行),并用于价值观或对象(MyClass x或aMyClass.方法())
所以如果你需要储存成为一个'Ford'变量(这一概念的价值)不同的亚类的福特,创建一个IFord.否则,不麻烦直到你真正需要它。
这是一个标准:如果它不能满足,IFord可能是无用的。
如果这是满足,那么其他条件暴露在先前的答案适用于:如果福特的具有丰富的API比汽车,IFord是有用的多态性的目的。如果不是,国际资产追回中心是不够的。
在我看来,界面是一种工具,可以强制要求一个类实现某个特征,或者(我喜欢这么认为)一个特定的“行为”。对我来说,我认为如果我的onterface开头的大写字母命名为人称代词,我试着命名我的界面,这样他们就可以这样读... ICanFly,IKnowHowToPersistMyself IAmDisplayable等...所以在你的例子中,我不会创建一个接口来镜像任何特定类的完整公共签名。我会分析公共签名(行为),然后将成员分成更小的逻辑组(越小越好),如(使用你的例子)IMove,IUseFuel,ICarryPassengers,ISteerable,IAccelerate,IDepreciate等......然后申请那些与我系统中其他类相关的接口需要它们
一般来说,考虑这个问题的最佳方式(以及OO中的许多问题)是考虑合同的概念。
合同被定义为两个(或多个)当事方之间的协议,规定了各方必须履行的具体义务;在程序中,这是一个类将提供的服务,以及为了获得服务而必须提供的类。接口声明了实现接口的任何类必须满足的契约。
考虑到这一点,您的问题在某种程度上取决于您使用的语言和您想要做的事情。
经过多年的OO(比如,天啊,30年),我通常会为每个合同编写一个接口,特别是在Java中,因为它使测试变得如此简单:如果我有一个类的接口,我几乎可以轻松地构建模拟对象。
接口旨在成为通用公共API,用户将被限制使用此公共API。除非您打算使用 IMustangGT
的类型特定方法,否则您可能希望将接口层次结构限制为 ICar
和 IExpensiveCar
。
仅从Interfaces和抽象类继承。
如果您有几个几乎相同的类,并且您需要实现大多数方法,请使用和Interface结合购买其他对象。 点击 如果Mustang类如此不同,那么不仅要创建一个接口ICar,还要创建IMustang 因此,福特和野马等级可以从ICar 和 IMustang继承ICar,Mustang和MustangGT。
如果您实施福特班并且方法与野马相同,请从野马购买:
class Ford{
public function Foo(){
...
Mustang mustang = new Mustang();
return mustang.Foo();
}