Dziedziczenie a miksy w dynamicznych językach?

19

Kiedy wolisz wzorce dziedziczenia niż miksy w dynamicznych językach?

Przez mixiny mam na myśli faktyczne właściwe wkomponowanie, tak jak wstawianie funkcji i elementów danych do obiektu w czasie wykonywania.

Kiedy użyjesz na przykład dziedziczenia prototypowego zamiast mixin? Aby lepiej zilustrować, co rozumiem przez mixin, pseudokod:

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

myObject = {}
asCircle(myObject)
myObject.area() // -> 0
Magnus Wolffelt
źródło
2
Mixiny bardziej przypominają aspekty przekrojowe niż dziedziczne dziedziczenie. To prawdopodobnie zdefiniuje dla ciebie kilka przypadków użycia.
ashes999
1
Kompozycja, ktokolwiek :)
OnesimusUnbound

Odpowiedzi:

14

Dziedziczenie prototypowe jest proste. Ma jedną przewagę nad mixinami.

To znaczy, że jest to link na żywo. jeśli zmienisz prototyp, wszystko, co go odziedziczy, zostanie zmienione.

Przykład użycia 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;
}

Zasadniczo więc jeśli chcesz, aby zmiany w kręgu „interfejsu” były odzwierciedlane w czasie wykonywania dla wszystkich obiektów, które „używają” jego funkcjonalności, to dziedzicz po niej.

Jeśli nie chcesz, aby zmiany odzwierciedlały, zmieszaj je.

Zauważ, że mixiny mają również większy cel. Mixiny są twoim mechanizmem wielokrotnego „dziedziczenia”.

Jeśli chcesz, aby obiekt zaimplementował wiele „interfejsów”, będziesz musiał je wmieszać. Ten, którego używasz do dziedziczenia prototypowego, to ten, dla którego zmiany mają być odzwierciedlone w czasie wykonywania, inne zostaną zmieszane.

Raynos
źródło
12

Mój zmysł konia mówi mi to:

  • Jeśli coś jest przydatne w wielu obiektach lub hierarchiach klas - zmień to w mixin
  • Jeśli coś jest nie tylko użyteczny wzdłuż pojedynczej hierarchii - wykorzystanie dziedziczenia

Powiązane uwagi:

  • Słowo „użyteczne” należy rozumieć metaforycznie
  • W przypadku języków, które nie mają wielokrotnego dziedziczenia, mixiny są dobrą alternatywą
  • PHP 5.4 wprowadza cechy, które mają dobro zarówno z miksów, jak i wielu światów dziedziczenia
treecoder
źródło
+1, moim ulubionym przykładem „czegoś użytecznego w wielu obiektach lub hierarchiach klas” w Ruby jest moduł Enumerable
David
1
Powiedziałbym, że wielokrotne dziedziczenie może być (niezbyt dobrą) alternatywą dla mixin.
Simon Bergot,
@ Simon Powiedziałbym, że mixiny mogą być (niezbyt dobrą) alternatywą dla wielokrotnego dziedziczenia;)
Raynos
Mój zmysł koni też mi to powiedział. :)
theringostarrs
9

Użyj testu „Is-a”.

Dziedziczenie ogranicza się do przypadku, gdy można powiedzieć „podklasa jest superklasą”. Są tego samego rodzaju. „Ser to produkt mleczny”.

Mixiny są do wszystkiego innego. „Ser może być stosowany w kanapce”. Ser nie jest kanapką, ale bierze udział w kanapce.

PS. Nie ma to nic wspólnego z dynamicznymi językami. Każdy język dziedziczenia wielokrotnego ze statyczną kompilacją (tj. C ++) ma ten sam punkt decyzji.

S.Lott
źródło
Zdecydowanie + 1-statyczne języki również mają mixiny.
DeadMG,
Zgadza się, mixiny można robić w wielu językach - to nie było moje pytanie. Języki dynamiczne mają pewne właściwości, które mogą sprawić, że miksy będą inne i / lub bardziej interesujące w takich językach - Raynos wskazał jeden aspekt. Co więcej, nie wskazujesz żadnych konkretnych powodów, dla których należy używać koncepcji IS A zamiast koncepcji mixin.
Magnus Wolffelt,
@MagnusWolffelt: Są tego samego rodzaju. „Ser to produkt mleczny”. Taka jest zasada dla IS-A. Co jeszcze powinienem powiedzieć?
S.Lott,
Moje pytanie dotyczy bardziej decyzji projektowych - w jakich sytuacjach chcesz dziedziczenia i z jakich powodów? W dynamicznych językach widzę kilka powodów, dla których warto wybierać dziedziczenie nad mixinami, oprócz tego, co opisał Raynos. Jednym z powodów może być wydajność tworzenia obiektów.
Magnus Wolffelt,
@MagnusWolffelt: „w jakich sytuacjach chcesz dziedziczenia” Kiedy dwie klasy spełniają relację IS-A. „Wydajność tworzenia obiektów” nie jest powodem do wybierania jednego z nich. Dziedziczenie stanowi bardzo mocne stwierdzenie o dwóch klasach obiektów. Mixins jest słabszym i bardziej elastycznym stwierdzeniem. Dziedziczenie stosuje się, gdy dwie klasy spełniają relację „IS-A”. Co jeszcze mogę powiedzieć? Nie rozumiem twojego pytania bardzo dobrze. Czy możesz wyjaśnić, co więcej chcesz wiedzieć?
S.Lott,
0

Cóż, najlepszym przykładem, jaki mogę ci dać, jest aktor dla gry, która ma dziedzictwo dla niektórych podstawowych rzeczy, ale używa mixin / wtyczek do wspólnej funkcjonalności. Współużytkowana funkcjonalność może być (bezpośrednio z kodu źródłowego!):

var plugins = {
    SingleVisualEntity : SingleVisualEntity,
    JumpBehaviour      : JumpBehaviour,
    WeaponBehaviour    : WeaponBehaviour,
    RadarBehaviour     : RadarBehaviour,
    EnergyGatherer     : EnergyGatherer,
    LifeBarPlugin      : LifeBarPlugin,
    SelectionPlugin    : SelectionPlugin,
    UpgradePlugin      : UpgradePlugin,
    BrainPlugin        : BrainPlugin,
    PlanetObjectPlugin : PlanetObjectPlugin,
}
Totty.js
źródło