为什么使用对象继承而不是 mixin

发布于 2024-12-05 04:47:12 字数 1109 浏览 1 评论 0原文

gist

相比 mixins 更倾向于继承的原因是什么

给出以下伪代码示例:

class Employee

class FullTimeEmployee inherits Employee

class PartTimeEmployee inherits Employee

// versus

class Employee

class WorksPartTime

class WorksFullTime

class FullTimeEmployee includes Employee, WorksFullTime
class PartTimeEmployee includes Employee, WorksPartTime

如果我们要使用继承来构建对象,类关系将被视为一棵树,而与 mixin 一样,类关系将被视为一个平面列表。

假设我们使用的语言

  • 允许使用非详细语法进行混合,
  • 这允许我们透明地将 FullTimeEmployee 视为 EmployeeFullTime 对象。

为什么我们应该将类关系建立为树(继承)而不是平面列表(组合)?

树与列表的示例。

class Person

class Employee inherits Person

class FullTimeEmployee inherits Employee

//                      -> FullTimeEmployee
//  Person -> Employee
//                      -> PartTimeEmployee

class Person

class Employee includes Person

class FullTime

class FullTimeEmployee includes FullTime, Employee

//
// FullTimeEmployee = (FullTime, Employee, Person)
//

gist

What are the reasons to favour inheritance over mixins

Given the following psuedo-code example :

class Employee

class FullTimeEmployee inherits Employee

class PartTimeEmployee inherits Employee

// versus

class Employee

class WorksPartTime

class WorksFullTime

class FullTimeEmployee includes Employee, WorksFullTime
class PartTimeEmployee includes Employee, WorksPartTime

If we were to use inheritance to build objects the class relations would be seen as a tree where as with mixins the class relations would be seen as a flat list.

Assuming the language we are using

  • allows for mixins with a non-verbose syntax
  • allows us to treat FullTimeEmployee as both a Employee and FullTime object transparently.

why should we build up our class relations as trees (inheritance) instead of flat lists (composition)?

Example of tree versus list.

class Person

class Employee inherits Person

class FullTimeEmployee inherits Employee

//                      -> FullTimeEmployee
//  Person -> Employee
//                      -> PartTimeEmployee

class Person

class Employee includes Person

class FullTime

class FullTimeEmployee includes FullTime, Employee

//
// FullTimeEmployee = (FullTime, Employee, Person)
//

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

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

发布评论

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

评论(3

晨曦慕雪 2024-12-12 04:47:12

我认为,在支持 mixins 的语言中,它实际上与使用(多重)继承相同。在这两种情况下,相关的类/对象上存在相同的方法/属性,两者的调用方式完全相同——没有实际区别。我还假设在这种假设的语言中,您也可以从多个“类”进行“扩展”。

如果这一切都是真的,那么在某种程度上它们是等效的,并且这个问题没有意义——没有一个比另一个更好,因为它们在功能上是等效的。

从人类理解的角度来看,我认为大多数人都认为继承是 isA 关系,混合是用功能来装饰某些东西。

如果您只能从一个“类”继承,那么显然 mixins 是一种获得多重继承的方法。

编辑——根据你的评论,这些评论很好,我想说假设语言的细节很重要。我承认我的答案是基于 Sproutcore,它是一个 Javascript 框架,对 mixin 和继承都提供了正式的支持。在 SC 中,您可以执行

App.MyObject = SC.Object.extend({
  prop: 'prop',
  func: function(){
})

您所期望的操作,它将 propfunc 放在 MyObject 的原型上,创建一个“类” ,它可以有子类。您还可以执行

App.MyObject = SC.Object.extend(App.OtherObject, {
   // stuff
})

多重继承。然后,您可以拥有类似的东西

CommonFunctionality = {
    // some methods
};

App.mixin(CommonFunctionality);

,将 CommonFunctionality 内容应用于 App。如果应用是一个命名空间(即 {}),则 CommonFunctionality 的方法将应用于该对象字面量。如果有意义的话,您还可以将 CommonFunctionality 应用于“类”,并且其方法将位于原型上。如果你查看源代码,你会看到

SC.extend = SC.mixin ;

所以在 SC 中,绝对没有区别,因为它们是相同的方法。

所以细节很重要——他们本来不必这样做,但他们这样做了,而且是有影响的。如果他们采取不同的做法,那么当然会产生不同的后果。

I would argue that in languages that do support mixins, it is effectively the same as using (multiple) inheritance. In both cases, the same methods/properties exist on the class/object in question, both are invoked the exact same way -- there is no practical distinction. I'm also assuming that in this hypothetical language, you can 'extend' from multiple 'classes' as well.

If this is all true, then in a way they are equivalent and the question doesn't make sense - neither is better than the other because they are functionality equivalent.

In a human-understanding sort of way, I think most people think of inheritance in terms of the isA relationship, and mixins in terms of decorating something with functionality.

If you can only inherit from one 'class', then obviously mixins are a way to sort of gain multiple inheritance.

EDIT -- based on your comments, which are good, I would say the details of the hypothetical language matter. I will admit I am basing my answer of the Sproutcore, which is a Javascript framework that has formalized support for both mixins and inheritance. In SC, you can do

App.MyObject = SC.Object.extend({
  prop: 'prop',
  func: function(){
})

which does what you would expect, it puts prop and func on the prototype of MyObject, creating a "class", which could have subclasses. You could also do

App.MyObject = SC.Object.extend(App.OtherObject, {
   // stuff
})

which does multiple inheritance. You could then have something like

CommonFunctionality = {
    // some methods
};

App.mixin(CommonFunctionality);

which would apply the CommonFunctionality stuff to App. If app was a namespace (i.e. a {}) the methods of CommonFunctionality would be applied to that object literal. If it made sense, you could also apply CommonFunctionality to a "class", and its methods would be on the prototype. If you look in the source, you see

SC.extend = SC.mixin ;

So in SC, there is absolutely no difference because they are the same method.

So details matter -- they didn't have to do it that way, but they did, and there are implications. If they had done it differently, then of course there would be different consequences.

眼前雾蒙蒙 2024-12-12 04:47:12

当有必要时你应该使用。如果您有一个包含 1000 行的大类,并且您发现自己在多个类中重复相同的内容,则可以将一些逻辑封装在基类中,将其他逻辑封装在 mixin 中。每个mixin都有有限的上下文,他们可能知道的比他们应该知道的多,但他们只专注于某个任务。因此非常模块化。
好吧,我可以给你的最好的例子是一个游戏的 Actor具有一些基本内容的继承,但使用 mixins/用于共享功能的插件。共享功能可以是(直接来自源代码!):

var plugins = {
    SingleVisualEntity : SingleVisualEntity,
    JumpBehaviour      : JumpBehaviour,
    WeaponBehaviour    : WeaponBehaviour,
    RadarBehaviour     : RadarBehaviour,
    EnergyGatherer     : EnergyGatherer,
    LifeBarPlugin      : LifeBarPlugin,
    SelectionPlugin    : SelectionPlugin,
    UpgradePlugin      : UpgradePlugin,
    BrainPlugin        : BrainPlugin,
    PlanetObjectPlugin : PlanetObjectPlugin,
}

这最初是一个包含 +1000 行的类。

You should use when the necessity appears. If you have a big class with 1000 lines and you are finding yourself repeating the same stuff across multiple classes you can encapsulate some logic in a base class and other in mixins. Each mixin has a limited context, they might be aware about more than they should, but they only focus on a certain task. Therefore are very modular.
Well, the best example I can give it to you is an Actor for a game which has inheritance for some base stuff but uses mixins/plugins for shared functionality. The shared functionality could be (directly from the source code!):

var plugins = {
    SingleVisualEntity : SingleVisualEntity,
    JumpBehaviour      : JumpBehaviour,
    WeaponBehaviour    : WeaponBehaviour,
    RadarBehaviour     : RadarBehaviour,
    EnergyGatherer     : EnergyGatherer,
    LifeBarPlugin      : LifeBarPlugin,
    SelectionPlugin    : SelectionPlugin,
    UpgradePlugin      : UpgradePlugin,
    BrainPlugin        : BrainPlugin,
    PlanetObjectPlugin : PlanetObjectPlugin,
}

This originally was a class with +1000 lines.

惯饮孤独 2024-12-12 04:47:12

在设计时,我们尝试尽可能模拟现实。

考虑到 is ahas a 原则,FullTimeEmployee 是具有附加(额外)功能的员工,并且不是除了所谓的FullTime之外还有员工的新事物,以及PartTimeEmployee 依此类推。

When designing we try to simulate reality as much as we can.

Considering the is a and the has a principles, a FullTimeEmployee is an Employee who has additional (extra) feature, and not some new thing that has an Employee beside something called FullTime, and so on for the PartTimeEmployee.

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