如何摆脱继承

发布于 2024-11-10 03:47:41 字数 419 浏览 3 评论 0原文

我在这里和其他论坛搜索过,但找不到好的答案。 我知道扩展类并不是最佳实践。我应该更多地使用接口。我的问题是,通常我开始创建接口,然后转移到抽象类,因为我总是想在超类上实现一些功能,这样我就不必在每个子类中复制它。 例如,我有一个车辆类以及汽车和自行车子类。很多功能可以在 Vehicle 类上实现,例如 Move() 和 Stop(),那么保持架构整洁、避免代码重复并使用接口而不是继承的最佳实践是什么? 多谢!

(如果您不知道我为什么问这个问题,您可以阅读这篇有趣的文章:http://www.javaworld.com/javaworld/jw-08-2003/jw-0801-toolbox.html

I've searched in here and other forums and couldn't find a good answer..
I kind of know that Extending classes isn't the best of practices. And that I should use Interfaces more. my problem is that usually I start creating Interfaces and then move to Abstract classes because there's always some functionality that I want implemented on a super class so that I don't have to replicate it in every child classes.
For instance, I have a Vehicle class and the Car and Bike child classes. a lot of functionality could be implemented on the Vehicle class, such as Move() and Stop(), so what would be the best practice to keep the architecture clean, avoid code repetition and use Interfaces instead of Inheritance?
Thanks a lot!

(if you have no idea why I'm asking this you may read this interesting article: http://www.javaworld.com/javaworld/jw-08-2003/jw-0801-toolbox.html)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

我还不会笑 2024-11-17 03:47:41

继承(“扩展类”)对类设计施加了很大的限制,并且我不确定使用接口来替代继承是最好的主意,因为它未通过 DRY 测试。

如今,组合比继承更受青睐,因此您可能会考虑这篇文章:更喜欢组合而不是继承?

Inheritance ('extending classes') imposes significant limitations on class design and I'm not sure the use of interfaces as a replacement for inheritance is the best idea since it fails the DRY test.

These days, Composition is favored over Inheritance, so you might consider this post: Prefer composition over inheritance?

萌吟 2024-11-17 03:47:41

有趣的问题。每个人都有不同的方法。但这一切都基于个人的经验和选择。

通常,我从一个接口开始,然后让一个抽象类继承该接口。并在那里实现共同的操作,并让继承该类的人来实现其他操作。

根据经验,这几乎没有什么好处,
1.在函数调用期间,您可以将元素作为接口类型或抽象类类型传递。
2.常用变量如ID、Names等可以放在抽象类中。
3.维护方便。例如,如果您想实现一个新接口,那么只需快速实现抽象即可。

Interesting question. Everyone has different approaches. But it all based on personal experience and choice.

Usually, i start with an interface, then let an abstract class inherit that interface. And implement common actions there, and let others to be implemented by who ever inherits this class.

This give few advantageous based on by experience,
1.During function calls you can pass the elements as interface type or abstract class type.
2.Common variables such as ID, Names etc can be put on abstract class.
3.Easy for maintenance. For example, if you want to implement a new interface, then just implement in the abstract quickly.

冷…雨湿花 2024-11-17 03:47:41

如果您牢记接口和类之间的根本区别,那么您将更容易决定使用哪一个。不同之处在于,接口仅表示所涉及的对象之间的协议(通常是行为的),而抽象类表示涉及某些部分(数据)的一些未完成的构造。以汽车为例,界面本质上是通用汽车的蓝图。抽象类就像预制的特定模型车身,需要填充剩余的部件才能得到最终产品。接口甚至不必是 Java 的——它不会改变任何东西——仍然是蓝图。

通常,您会在特定的实现框架中使用抽象类来为其使用者提供一些基本功能。如果您只是声明您从不使用抽象类而使用接口 - 从实际角度来看,这显然是错误的。如果您需要 10 个相同接口的实现且 90% 的代码相同,该怎么办?复制代码10次?好吧,也许你会在这里使用抽象类,但将接口放在它上面。但是,如果您从未打算向外部消费者提供类层次结构,为什么要这样做呢?
我在非常广泛的意义上使用外部这个词 - 它可以只是您的项目或远程消费者中的不同包。

归根结底,其中许多都是偏好和个人经历,但我不同意大多数笼统的说法,例如 extends is ill。我也不想使用额外的类(接口或抽象),除非设计的特定部分需要。

只是我的两分钱。

If you keep in mind fundamental difference between interfaces and classes it will make it easier to decide which one to use. The difference is that interfaces represent just a protocol (usually behavioral) between objects involved, while abstract classes represent some unfinished constructions that involve some parts (data). In car example, interface is essentially a blueprint for the generic car. And abstract class would be like prefabricated specific model car body that needs to be filled with remaining parts to get final product. Interfaces don't even have to be in Java - it will not change anything - still blueprint.

Typically you would use abstract class within your specific implementation framework to provide its consumers with some basic functionality. If you just state that you never use abstract class in favor of interface - it's plain wrong from practical standpoint. What if you need 10 implementations of the same interface with 90% of the same code. Replicate code 10 times? Ok, may be you would use abstract class here but put interface on top of it. But why would you do that if you never intend to offer your class hierarchy to external consumers?
I am using word external in very wide sense - it can be just different package in your project or remote consumer.

Ultimately, many of those things are preferences and personal experiences, but I disagree with most blanket statements like extends is evil. I also prefer not to use extra classes (interfaces or abstract) unless it is required by specific parts of the design.

Just my two cents.

荒路情人 2024-11-17 03:47:41

继承允许代码重用和可替换性,但限制多态性。组合允许代码重用,但不允许替换。接口允许可替换性,但不允许代码重用。

决定是否使用继承、组合或接口可以归结为几个简单的原则:

  1. 如果需要代码重用性和可替换性,并且对多态性的限制还不错,请使用继承。
  2. 如果需要代码重用,但不需要可替代性,请使用组合。
  3. 如果需要可替换性,但不需要代​​码重用,或者如果继承对多态性施加的限制比重复代码更糟糕,请使用接口。
  4. 如果需要可替换性和代码重用,但多态性带来的限制是不可接受的,请使用接口来包装封装的对象。
  5. 如果需要可替换性和代码重用,并且多态性施加的限制不会造成任何直接问题,但可能对未来的可替换类造成问题,请派生一个实现接口的模型基类,并让那些可以从它派生的类这样做。不过,请避免使用类类型的变量和参数,而应使用接口。如果这样做,并且需要一个不能很好地从模型基类派生的可替代类,则新类可以实现该接口,而不必从基类继承;如果需要,它可以通过包装模型类型派生的封装实例来实现接口。

在决定未来的可替代类是否难以从基类派生时可能需要做出判断。不过,当需要可替代性时,我倾向于认为方法#5 通常提供最好的方法。它通常比单独使用接口便宜,并且比单独使用继承贵不了多少。如果未来需要可替换但不能从基类派生的类,则可能需要将代码转换为使用方法 #5。从一开始就使用方法 #5 将避免稍后重构代码。 (当然,如果不需要替换无法从基类派生的类,则额外的成本(尽管可能很小)最终可能是不必要的)。

Inheritance allows code reuse and substitutability, but restricts polymorphism. Composition allows code reuse but not substitutability. Interfaces allow substitutability but not code reuse.

The decision of whether to use inheritance, composition, or interfaces, boils down to a few simple principles:

  1. If one needs both code reuse and substitutability, and the restrictions imposed on polymorphism aren't too bad, use inheritance.
  2. If one needs code reuse, but not substitutability, use composition.
  3. If one needs substitutability, but not code reuse, or if the restrictions inheritance would impose upon polymorphism would be worse than duplicated code, use interfaces.
  4. If one needs substitutability and code reuse, but the restrictions imposed by polymorphism would be unacceptable, use interfaces to wrap encapsulated objects.
  5. If one needs substitutability and code reuse, and the restrictions imposed by polymorphism would not pose any immediate problem but might be problematic for future substitutable classes, derive a model base class which implements an interface, and have those classes that can derive from it do so. Avoid using variables and parameters of the class type, though--use the interface instead. If you do that, and there is a need for a substitutable class which cannot very well derive from the model base class, the new class can implement the interface without having to inherit from the base; if desired, it may implement the interface by wrapping an encapsulated instance of a derivative of the model type.

Judgment may be required in deciding whether future substitutable classes may have difficulty deriving from a base class. I tend to think approach #5 often offers the best of all worlds, though, when substitutability is required. It's often cheaper than using interfaces alone, and not much more expensive than using inheritance alone. If there is a need for future classes which are substitutable but cannot be derived from the base, it may be necessary to convert the code to use approach #5. Using approach #5 from the get-go would avoid having to refactor the code later. (Of course, if it's never necessary to substitute a class that can't derive from the base, the extra cost--slight as it may be--may end up being unnecessary).

耶耶耶 2024-11-17 03:47:41

同意 tofutim - 在您当前的示例中,在车辆上移动和停止是合理的。

读完这篇文章后 - 我认为它使用强大的语言来推动一个观点......记住 - 继承是帮助完成工作的工具。

但是,如果我们假设出于某种原因您在这种情况下不能/不会使用该工具,那么您可以首先将其分解为带有辅助对象和/或访问者的小接口......

例如 -
车辆类型包括潜艇、船、飞机、汽车和自行车。您可以将其分解为接口...
可移动
+ 转发()
+ 向后()
+ 向左()
+ Right()

IFloatable
+ Dock()

ISink()
+ 吹气()

IFly()
+ 起飞()
+ Land()

然后您的类可以聚合您刚刚定义的大量接口。

问题是,您最终可能会在汽车/自行车类中为 IMoveable.Left() 和 IMoveable.Right() 重复一些代码。您可以将其分解为帮助器方法并聚合该帮助器...但是如果您遵循它的逻辑结论,您最终仍然会将许多内容重构回基类中。

继承和聚合都是工具……两者都不是“邪恶的”。

希望有帮助。

Agree with tofutim - in your current example, move and stop on Vehicle is reasonable.

Having read the article - I think it's using powerful language to push a point... remember - inheritance is a tool to help get a job done.

But if we go with the assumption that for whatever reasons you can't / won't use the tool in this case, you can start by breaking it down into small interfaces with helper objects and/or visitors...

For example -
Vehicle types include submarine, boat, plane, car and bike. You could break it down into interfaces...
IMoveable
+ Forward()
+ Backward()
+ Left()
+ Right()

IFloatable
+ Dock()

ISink()
+ BlowAir()

IFly()
+ Takeoff()
+ Land()

And then your classes can aggregate the plethora of interfaces you've just defined.

The problem is though that you may end up duplicating some code in the car / bike class for IMoveable.Left() and IMoveable.Right(). You could factor this into a helper method and aggregate the helper... but if you follow it to its logical conclusion, you would still end up refactoring many things back into base classes.

Inheritance and Aggregation are tools... neither of which are "evil".

Hope that helps.

心如狂蝶 2024-11-17 03:47:41

您想要针对您的具体情况还是一般情况的答案?在您描述的情况下,使用抽象类没有任何问题。当所有客户端都需要为 Move() 和 Stop() 实现完全相同的代码时,使用接口是没有意义的。

Do you want an answer for your specific case, or in general? In the case you described, there is nothing wrong with using an Abstract class. It doesn't make sense use an interface when all of the clients would need to implement the exact same code for Move() and Stop().

迷你仙 2024-11-17 03:47:41
  • 不要相信你读到的一切

    • 很多时候,继承并不是坏事,事实上,对于数据隐藏来说,继承可能是一个好主意。
  • 基本上,当你创建一个非常小的类树时,只使用“仅接口”的策略,否则,我保证这会很痛苦。假设您有一个 Person“类”(具有 eat()sleep),并且有两个子类 Mathematician (具有 doProblem() )和工程师(buildSomething()),然后使用接口。如果您需要诸如 Car 类之类的东西,然后需要 56 种汽车类型,那么请选择继承。基本上

恕我直言。

  • Don't believe all you read

    • Many times, inheritance is not bad, in fact, for data-hiding, it may be a good idea.
  • Basically, only use the policy of "interfaces only" when you're making a very small tree of classes, otherwise, I promise it will be a pain. Suppose you have a Person "class" (has eat() and sleep), and there are two subclasses, Mathematician (has doProblem() ) and Engineer ( buildSomething() ), then go with interfaces. If you need something like a Car class and then 56 bazillion types of cars, then go with inheritance.

IMHO.

远昼 2024-11-17 03:47:41

我认为,接口有时也是邪恶的。它们可以避免多重继承。

但如果我们将接口与抽象类进行比较,那么抽象类总是比接口更多。接口始终是类的某些方面——某种观点,而不是作为类的整体。

所以我认为你不应该避免继承并在任何地方使用 iterfaces —— 应该保持平衡。

I think, that Interfaces sometime also evil. They could be as avoidance of multiple inheritance.

But if we compare interface with abstract class, then abstract class is always more than interface. Interface is always some aspect of the class -- some viewpoint, and not whole as a class.

So I don't think you should avoid inheritance and use iterfaces everywhere -- there should be balance.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文