Наследование против миксинов в динамических языках?

19

Когда следует предпочитать шаблоны наследования миксинам в динамических языках?

Под миксинами я имею в виду собственно правильное микширование, как при вставке функций и элементов данных в объект во время выполнения.

Когда бы вы использовали, например, наследование прототипа вместо миксинов? Чтобы проиллюстрировать, что я имею в виду под mixin, приведем псевдокод:

asCircle(obj) {
  obj.radius = 0
  obj.area = function() {
    return this.radius * this.radius * 3.14
  }

myObject = {}
asCircle(myObject)
myObject.area() // -> 0
Магнус Вольффелт
источник
2
Миксины больше похожи на сквозные аспекты, чем на прямое наследование. Это, вероятно, определит некоторые варианты использования для вас.
ashes999
1
Композиция, кто угодно :)
OnesimusUnbound

Ответы:

14

Прототип наследования прост. У него есть одно преимущество перед миксинами.

Это то, что это живая ссылка. если вы измените прототип, все, что наследует его, изменится.

Пример использования pd

var Circle = {
  constructor: function _constructor() {
    this.radius = 0;
    return this;
  },
  area: function _area() {
    return this.radius * this.radius * Circle.PI
  },
  PI: 3.14
};

var mixedIn = pd.extend({}, Circle).constructor();
var inherited = pd.make(Circle, {}).constructor();

Circle.perimeter = perimeter;

inherited.perimeter(); // wins
mixedIn.perimeter(); // fails

function perimeter() {
  return 2 * this.radius;
}

В общем, если вы хотите, чтобы изменения в круге «interface» отражали во время выполнения все объекты, которые «используют» его функциональность, то наследуйте от него.

Если вы не хотите, чтобы изменения отражали, смешайте их.

Обратите внимание, что миксины также имеют большее назначение. Миксины - это ваш механизм множественного «наследования».

Если вы хотите, чтобы объект для реализации несколько «интерфейсов» , то вы будете должны смешивать некоторые в. Тот , который вы используете для прототипа наследования является тот , который вы хотите изменения , чтобы отразить на время выполнения, другие будут смешаны в.

Raynos
источник
12

Мое чувство лошади говорит мне это:

  • Если что-то полезно для нескольких объектов или иерархий классов - сделайте это смешанным
  • Если что - то только полезно по одной иерархии - использование наследования

Связанные заметки:

  • Слово «полезный» следует понимать метафорически
  • Для тех языков, которые не имеют множественного наследования, миксины являются хорошей альтернативой
  • В PHP 5.4 представлены черты , которые хорошо сочетаются как с миксинами, так и с множественным наследованием.
treecoder
источник
+1, мой любимый пример «чего-то полезного для нескольких объектов или иерархий классов» в Ruby - это модуль Enumerable: ruby-doc.org/core-1.9.3/Enumerable.html
Дэвид
1
Я бы сказал, что множественное наследование может быть (не очень хорошей) альтернативой миксинам.
Саймон Бергот
@ Симон Я бы сказал, что миксины могут быть (не очень хорошей) альтернативой множественному наследованию;)
Raynos
Моё чувство лошади сказало мне это тоже. :)
theringostarrs
9

Используйте тест "Is-a".

Наследование ограничено случаем, когда вы можете сказать «Подкласс - это Суперкласс». Они такие же вещи. «Сыр - молочный продукт».

Mixins для всего остального. «Сыр можно использовать в бутерброде». Сыр не бутерброд, но он участвует в бутерброде.

PS. Это не имеет ничего общего с динамическими языками. Любой язык множественного наследования со статической компиляцией (т. Е. C ++) имеет ту же точку принятия решения.

С. Лотт
источник
Определенно + 1- статические языки тоже имеют миксины.
DeadMG
Да, миксины можно делать на многих языках - это был не мой вопрос. Динамические языки имеют определенные свойства, которые могут или не могут сделать миксины различными и / или более интересными в таких языках - Рейнос указал на один аспект. Кроме того, вы не указываете каких-либо конкретных причин, по которым следует использовать концепцию IS A вместо концепции mixin.
Магнус Вольффелт
@MagnusWolffelt: Это одно и то же. «Сыр - молочный продукт». Это правило для IS-A. Что еще мне сказать?
С.Лотт
Мой вопрос больше касается проектных решений - в каких ситуациях вы хотите наследования и по каким причинам? В динамических языках я вижу несколько причин для выбора наследования по миксинам, помимо того, что описал Рейнос. Производительность создания объекта может быть одной из причин.
Магнус Вольффелт
@MagnusWolffelt: «в каких ситуациях вы хотите наследовать», когда два класса удовлетворяют отношениям IS-A. «Производительность создания объекта» не является причиной выбора одного над другим. Наследование делает очень сильное утверждение о двух классах объектов. Mixins делает более слабое и более гибкое утверждение. Наследование используется, когда два класса удовлетворяют соотношению «IS-A». Что еще я могу сказать? Я не очень хорошо понимаю ваш вопрос. Можете ли вы уточнить, что еще вы хотели бы знать?
S.Lott
0

Что ж, лучший пример, который я могу вам дать, - это актер для игры, который имеет наследство для некоторых базовых вещей, но использует миксины / плагины для общей функциональности. Общая функциональность может быть (прямо из исходного кода!):

var plugins = {
    SingleVisualEntity : SingleVisualEntity,
    JumpBehaviour      : JumpBehaviour,
    WeaponBehaviour    : WeaponBehaviour,
    RadarBehaviour     : RadarBehaviour,
    EnergyGatherer     : EnergyGatherer,
    LifeBarPlugin      : LifeBarPlugin,
    SelectionPlugin    : SelectionPlugin,
    UpgradePlugin      : UpgradePlugin,
    BrainPlugin        : BrainPlugin,
    PlanetObjectPlugin : PlanetObjectPlugin,
}
Totty.js
источник