Herança vs mixins em idiomas dinâmicos?


19

Quando você deve preferir padrões de herança a mixins em linguagens dinâmicas?

Por mixins, refiro-me à mistura adequada real, como na inserção de funções e membros de dados em um objeto em tempo de execução.

Quando você usaria, por exemplo, herança prototípica em vez de mixins? Para ilustrar mais claramente o que quero dizer com mixin, alguns pseudocódigo:

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

myObject = {}
asCircle(myObject)
myObject.area() // -> 0

2
Os mixins são mais como aspectos transversais do que herança direta. Isso provavelmente definirá alguns casos de uso para você.
precisa saber é o seguinte

1
Composição, ninguém :)
OnesimusUnbound

Respostas:


14

A herança prototípica é simples. Tem uma vantagem única sobre mixins.

Isso é que é um link ao vivo. se você alterar o protótipo, tudo o que herdar será alterado.

Exemplo usando 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;
}

Então, basicamente, se você deseja que as alterações no círculo da "interface" sejam refletidas no tempo de execução para todos os objetos que "usam" sua funcionalidade, herda-a.

Se você não quiser que as alterações sejam refletidas, misture-as.

Observe que os mixins também têm mais finalidade do que isso. Mixins são o seu mecanismo para múltiplas "heranças".

Se você quer um objeto para implementar várias "interfaces", então você vai ter que misturar um pouco. O que você usa para a herança prototípica é o que você quer mudanças para refletir para em tempo de execução, os outros serão misturado.


12

Meu senso de cavalo me diz isso:

  • Se algo é útil em vários objetos ou hierarquias de classes - faça uma combinação
  • Se algo for útil em uma única hierarquia - use herança

Notas relacionadas:

  • A palavra "útil" deve ser tomada metaforicamente
  • Para os idiomas que não têm herança múltipla, os mixins são uma boa alternativa
  • O PHP 5.4 introduz traços que têm bondade de mixins e vários mundos de herança

+1, meu exemplo favorito de "algo útil em vários objetos ou hierarquias de classes" no Ruby é o módulo Enumerable: ruby-doc.org/core-1.9.3/Enumerable.html
David

1
Eu diria que a herança múltipla pode ser uma alternativa (não tão boa) aos mixins.
Simon Bergot

@Simon eu diria que mixins pode ser uma (não tão bom) alternativa para herança múltipla;)
Raynos

Meu senso de cavalo também me disse isso. :)
theringostarrs

9

Use o teste "Is-a".

A herança é limitada ao caso em que você pode dizer "Subclasse É Uma Superclasse". Eles são o mesmo tipo de coisa. "O queijo é um produto lácteo".

Mixins são para todo o resto. "O queijo pode ser usado em um sanduíche". O queijo não é um sanduíche, mas participa do sanduíche.

PS. Isso não tem nada a ver com linguagens dinâmicas. Qualquer linguagem de herança múltipla com compilação estática (ou seja, C ++) tem o mesmo ponto de decisão.


Definitivamente + 1 - linguagens estáticas também têm mixins.
DeadMG 6/12/11

Certo, mixins podem ser feitos em vários idiomas - essa não foi minha pergunta. Linguagens dinâmicas têm certas propriedades que podem ou não tornar os mixins diferentes e / ou mais interessantes nessas linguagens - Raynos apontou um aspecto. Além disso, você não aponta razões específicas para usar o conceito IS A sobre o conceito mixin.
Magnus Wolffelt

@MagnusWolffelt: Eles são o mesmo tipo de coisa. "O queijo é um produto lácteo". Essa é a regra para o IS-A. O que mais devo dizer?
S.Lott

Minha pergunta é mais sobre decisões de design - em quais situações você deseja herança e por que razões? Nas linguagens dinâmicas, vejo poucas razões para escolher herança sobre mixins, além do que Raynos descreveu. O desempenho da criação de objetos pode ser um dos motivos.
Magnus Wolffelt

@MagnusWolffelt: "em que situações você deseja herança" Quando as duas classes satisfazem o relacionamento IS-A. "Desempenho da criação de objeto" não é um motivo para escolher um sobre o outro. A herança faz uma afirmação muito forte sobre as duas classes de objetos. Mixins faz uma declaração mais fraca e mais flexível. A herança é usada quando as duas classes satisfazem o relacionamento "IS-A". O que mais eu poderia dizer? Não consigo entender sua pergunta muito bem. Você pode esclarecer o que mais gostaria de saber?
S.Lott

0

Bem, o melhor exemplo que posso dar a você é um ator de um jogo que tem herança para algumas coisas básicas, mas usa mixins / plugins para funcionalidade compartilhada. A funcionalidade compartilhada pode ser (diretamente do código-fonte!):

var plugins = {
    SingleVisualEntity : SingleVisualEntity,
    JumpBehaviour      : JumpBehaviour,
    WeaponBehaviour    : WeaponBehaviour,
    RadarBehaviour     : RadarBehaviour,
    EnergyGatherer     : EnergyGatherer,
    LifeBarPlugin      : LifeBarPlugin,
    SelectionPlugin    : SelectionPlugin,
    UpgradePlugin      : UpgradePlugin,
    BrainPlugin        : BrainPlugin,
    PlanetObjectPlugin : PlanetObjectPlugin,
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.