我在这里和其他论坛搜索过,找不到一个好的答案.. 我知道扩展课程不是最好的练习。我应该更多地使用Interfaces。我的问题是通常我开始创建接口然后转移到抽象类,因为我总是希望在超类上实现一些功能,这样我就不必在每个子类中复制它。 例如,我有一个Vehicle类和Car and Bike子类。可以在Vehicle类上实现很多功能,例如Move()和Stop(),那么保持架构清洁,避免代码重复和使用接口而不是继承的最佳做法是什么? 非常感谢!
(如果你不知道为什么我问这个你可能会读到这篇有趣的文章:http://www.javaworld.com/javaworld/jw-08-2003/jw-0801-toolbox.html)
答案 0 :(得分:3)
继承('扩展类')对类设计施加了很大的限制,我不确定使用接口作为继承的替代是最好的主意,因为它没有通过DRY测试。
这些天,Composition比继承更受欢迎,所以你可以考虑这篇文章:Prefer composition over inheritance?
答案 1 :(得分:2)
有趣的问题。每个人都有不同的方法。但这一切都基于个人经验和选择。
通常,我从一个接口开始,然后让一个抽象类继承该接口。并在那里实施共同的行动,并让其他人继承这个类。
根据经验,这几乎没有优势,
1.在函数调用期间,您可以将元素作为接口类型或抽象类类型传递
2. ID,名称等常用变量可以放在抽象类上
3.易于维护。例如,如果要实现新接口,则只需快速实现摘要。
答案 2 :(得分:1)
如果你记住接口和类之间的根本区别,它将更容易决定使用哪一个。不同之处在于接口仅表示所涉及对象之间的协议(通常是行为),而抽象类表示涉及某些部分(数据)的一些未完成的构造。在汽车示例中,界面本质上是通用汽车的蓝图。抽象类就像预制的特定模型车身,需要填充剩余部分才能获得最终产品。接口甚至不必是Java - 它不会改变任何东西 - 仍然是蓝图。
通常,您将在特定的实现框架中使用抽象类来为其使用者提供一些基本功能。如果你只是说你从不使用抽象类来支持接口 - 从实际的角度来看,这是完全错误的。如果您需要10个相同接口的实现以及90%相同代码,该怎么办?复制代码10次?好吧,可能你会在这里使用抽象类,但把接口放在它上面。但是,如果您从未打算向外部消费者提供您的类层次结构,为什么还要这样做呢? 我在很广泛的意义上使用外部词 - 它可能只是你项目中的不同包或远程消费者。
归根结底,很多事情都是偏好和个人经历,但我不赞同大多数一揽子陈述,如extends is evil
。我也不想使用额外的类(接口或抽象),除非设计的特定部分需要它。
只是我的两分钱。
答案 3 :(得分:1)
继承允许代码重用和可替代性,但限制多态性。组合允许代码重用但不具有可替代性。接口允许替代性,但不允许代码重用。
是否使用继承,组合或接口的决定归结为几个简单的原则:
在决定未来可替代类别是否可能难以从基类派生时,可能需要作出判断。我倾向于认为方法#5经常提供所有世界中最好的,当需要可替代性时。它通常比单独使用接口便宜,而且比单独使用继承要便宜得多。如果需要可替代但不能从基础派生的未来类,则可能需要将代码转换为使用方法#5。使用get-go中的方法#5可以避免以后重构代码。 (当然,如果从来没有必要替换不能从基础派生的类,那么额外的成本 - 尽管可能很小 - 最终可能是不必要的。)
答案 4 :(得分:0)
您想要针对您的具体案例或一般情况的答案吗?在您描述的情况下,使用Abstract类没有任何问题。当所有客户端需要为Move()和Stop()实现完全相同的代码时,使用接口是没有意义的。
答案 5 :(得分:0)
不要相信你所读的全部内容
基本上,当你制作一个非常小的类树时,只使用“仅接口”的策略,否则,我保证会很痛苦。假设您有一个Person“class”(包含eat()
和sleep
),并且有两个子类,Mathematician(有doProblem()
)和Engineer
(buildSomething()
),然后去接口。如果您需要类似汽车级别的汽车,然后需要56种汽车,那么请继续使用。
IMHO。
答案 6 :(得分:0)
同意tofutim - 在您当前的示例中,移动和停止在Vehicle上是合理的。
阅读完文章后 - 我认为它正在使用强大的语言来突破重点......记住 - 继承是一种帮助完成工作的工具。
但是如果我们假设无论出于何种原因你不能/不会在这种情况下使用该工具,你可以先把它分解成带有辅助对象和/或访问者的小界面...... / p>
例如 - 车型包括潜艇,船,飞机,汽车和自行车。你可以把它分解成接口...... IMoveable +前进() +向后() +左() +右()
IFloatable + Dock()
ISINK() + BlowAir()
IFLY() +起飞() + Land()
然后你的类可以聚合你刚刚定义的过多接口。
问题是你最终可能会在汽车/自行车类中为IMoveable.Left()和IMoveable.Right()复制一些代码。您可以将其纳入辅助方法并聚合帮助程序......但是如果您遵循它的逻辑结论,您仍然会将很多东西重构为基类。
继承和聚合是工具......两者都不是“邪恶的”。
希望有所帮助。
答案 7 :(得分:0)
我认为,接口有时也是邪恶的。它们可以避免多重继承。
但是如果我们将接口与抽象类进行比较,那么抽象类总是比接口更多。接口总是类的一些方面 - 一些观点,而不是整个类。
所以我认为你不应该避免继承并在任何地方使用它们 - 应该有平衡。