Pewarisan vs mixin dalam bahasa dinamis?

19

Kapan sebaiknya Anda lebih suka pola pewarisan daripada mixin dalam bahasa dinamis?

Dengan mixins, maksud saya pencampuran yang tepat, seperti dalam menyisipkan fungsi dan anggota data ke dalam objek di runtime.

Kapan Anda akan menggunakan, misalnya, pewarisan prototypal alih-alih mixin? Untuk menggambarkan lebih jelas apa yang saya maksud dengan mixin, beberapa pseudocode:

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

myObject = {}
asCircle(myObject)
myObject.area() // -> 0
Magnus Wolffelt
sumber
2
Mixin lebih seperti aspek lintas bidang daripada pewarisan langsung. Itu mungkin akan menentukan beberapa kasus penggunaan untuk Anda.
ashes999
1
Komposisi, siapa pun :)
OnesimusUnbound

Jawaban:

14

Warisan prototipe sederhana. Ini memiliki keunggulan tunggal dibandingkan mixin.

Itu adalah tautan langsung. jika Anda mengubah prototipe semua yang mewarisi itu diubah.

Contoh menggunakan 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;
}

Jadi pada dasarnya, jika Anda ingin perubahan pada "antarmuka" Lingkaran untuk mencerminkan pada saat dijalankan untuk semua objek yang "menggunakan" fungsinya, maka mewarisi darinya.

Jika Anda tidak ingin perubahan direfleksikan maka campurlah.

Perhatikan bahwa mixin memiliki tujuan lebih dari itu juga. Mixin adalah mekanisme Anda untuk beberapa "warisan".

Jika Anda ingin objek untuk mengimplementasikan beberapa "interface" maka Anda akan harus mencampur beberapa di. Yang Anda gunakan untuk warisan prototipikal adalah salah satu yang ingin perubahan untuk merefleksikan selama run-time, yang lain akan dicampur dalam.

Raynos
sumber
12

Perasaan kuda saya memberi tahu saya ini:

  • Jika sesuatu bermanfaat di banyak objek atau hierarki kelas - jadikan itu mixin
  • Jika sesuatu hanya bermanfaat di sepanjang hierarki tunggal - gunakan warisan

Catatan terkait:

  • Kata "berguna" harus diambil secara metaforis
  • Untuk bahasa-bahasa yang tidak memiliki banyak pewarisan, mixin adalah alternatif yang baik
  • PHP 5.4 memperkenalkan sifat - sifat yang memiliki kebaikan dari mixin dan dunia pewarisan berganda
treecoder
sumber
+1, contoh favorit saya tentang "sesuatu yang berguna di banyak objek atau hierarki kelas" di Ruby adalah modul Enumerable: ruby-doc.org/core-1.9.3/Enumerable.html
David
1
Saya akan mengatakan bahwa multiple inheritance dapat menjadi alternatif (tidak begitu baik) untuk mixin.
Simon Bergot
@Simon Saya akan mengatakan bahwa mixin dapat menjadi (tidak begitu baik) alternatif untuk multiple inheritance;)
Raynos
Perasaan kuda saya mengatakan ini juga kepada saya. :)
theringostarrs
9

Gunakan tes "Is-a".

Warisan terbatas pada kasus ketika Anda dapat mengatakan "Subclass IS A Superclass". Mereka adalah hal yang sama. "Keju adalah Produk Susu".

Mixin adalah untuk segala sesuatu yang lain. "Keju bisa digunakan dalam sandwich". Keju bukan sandwich, tetapi berpartisipasi dalam sandwich.

PS. Ini tidak ada hubungannya dengan bahasa dinamis. Setiap bahasa pewarisan berganda dengan kompilasi statis (yaitu, C ++) memiliki titik keputusan yang sama.

S.Lott
sumber
Jelas + 1- bahasa statis juga memiliki mixin.
DeadMG
Benar, mixin dapat dilakukan dalam banyak bahasa - ini bukan pertanyaan saya. Bahasa dinamis memiliki sifat-sifat tertentu yang mungkin atau mungkin tidak membuat mixin berbeda dan / atau lebih menarik dalam bahasa tersebut - Raynos menunjuk satu aspek keluar. Selain itu, Anda tidak menunjukkan alasan spesifik mengapa seseorang harus menggunakan konsep IS A di atas konsep mixin.
Magnus Wolffelt
@MagnusWolffelt: Mereka adalah hal yang sama. "Keju adalah Produk Susu". Itulah aturan untuk IS-A. Apa lagi yang harus saya katakan?
S.Lott
Pertanyaan saya lebih lanjut tentang keputusan desain - dalam situasi apa Anda menginginkan warisan, dan untuk alasan apa? Dalam bahasa yang dinamis, saya melihat beberapa alasan untuk memilih warisan daripada mixin, selain yang dijelaskan oleh Raynos. Kinerja penciptaan objek mungkin menjadi salah satu alasan.
Magnus Wolffelt
@MagnusWolffelt: "dalam situasi apa Anda menginginkan warisan" Ketika kedua kelas memenuhi hubungan IS-A. "Kinerja penciptaan objek" bukan alasan untuk memilih satu dari yang lain. Warisan membuat pernyataan yang sangat kuat tentang dua kelas objek. Mixin membuat pernyataan yang lebih lemah dan lebih fleksibel. Warisan digunakan ketika dua kelas memenuhi hubungan "IS-A". Apa lagi yang bisa saya katakan? Saya tidak bisa memahami pertanyaan Anda dengan sangat baik. Bisakah Anda mengklarifikasi apa lagi yang ingin Anda ketahui?
S.Lott
0

Nah, contoh terbaik yang bisa saya berikan kepada Anda adalah Aktor untuk game yang memiliki warisan untuk beberapa hal dasar tetapi menggunakan mixins / plugins untuk fungsi bersama. Fungsi yang dibagikan dapat (langsung dari kode sumber!):

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