Warisan, Polimorfisme, dan Enkapsulasi adalah tiga fitur paling penting dan paling penting dari OOP, dan dari mereka, pewarisan memiliki statistik penggunaan yang tinggi dewasa ini. Saya sedang belajar JavaScript, dan di sini, mereka semua mengatakan bahwa ia memiliki warisan prototipal, dan orang-orang di mana-mana mengatakan bahwa itu adalah sesuatu yang jauh berbeda dari warisan klasik.
Namun, saya tidak dapat memahami apa perbedaan mereka dari sudut penggunaan praktis? Dengan kata lain, ketika Anda mendefinisikan kelas dasar (prototipe) dan kemudian mengambil beberapa subclass dari itu, Anda berdua memiliki akses ke fungsionalitas kelas dasar Anda, dan Anda dapat menambah fungsi pada kelas turunan. Jika kita menganggap apa yang saya katakan sebagai hasil yang dimaksudkan dari warisan, lalu mengapa kita harus peduli jika kita menggunakan versi prototypal atau klasik?
Untuk lebih jelas, saya tidak melihat perbedaan dalam kegunaan dan pola penggunaan prototipe dan pewarisan klasik. Ini membuat saya tidak tertarik untuk mempelajari mengapa mereka berbeda, karena keduanya menghasilkan hal yang sama, OOAD. Bagaimana praktis (bukan secara teoritis) pewarisan prototypal berbeda dari warisan klasik?
sumber
Warisan klasik mewarisi perilaku, tanpa status apa pun, dari kelas induk. Itu mewarisi perilaku pada saat objek dipakai.
Warisan prototipe mewarisi perilaku dan negara dari objek induk. Ini mewarisi perilaku dan keadaan saat objek dipanggil. Ketika objek induk berubah pada saat run-time, keadaan dan perilaku objek anak terpengaruh.
"Keuntungan" dari pewarisan prototypal adalah bahwa Anda dapat "menambal" keadaan dan perilaku setelah semua objek Anda dipakai. Sebagai contoh, dalam kerangka Ext JS itu umum untuk memuat "menimpa" yang menambal komponen inti kerangka kerja setelah kerangka kerja telah dipakai.
sumber
class C(object): def m(self, x): return x*2
daninstance = C()
kemudian ketika saya menjalankaninstance.m(3)
saya dapatkan6
. Tetapi jika saya kemudian mengubahnyaC
jadiC.m = lambda s, x: x*x
dan saya jalankaninstance.m(3)
sekarang saya dapatkan9
. Hal yang sama berlaku jika saya membuatclass D(C)
dan mengubah metode,C
maka setiap contohD
menerima metode yang diubah juga. Apakah saya salah paham atau apakah ini berarti bahwa Python tidak memiliki warisan Klasik menurut definisi Anda?Pertama: Sebagian besar waktu, Anda akan menggunakan objek, tidak mendefinisikannya, dan menggunakan objek adalah sama di bawah kedua paradigma.
Kedua: Sebagian besar lingkungan prototypal menggunakan divisi yang sama dengan lingkungan berbasis kelas - data yang dapat diubah pada instance, dengan metode yang diwarisi. Jadi ada sedikit perbedaan lagi. (Lihat jawaban saya untuk pertanyaan stack overflow ini , dan Program Pengorganisasian Kertas Mandiri Tanpa Kelas . Lihatlah Citeseer untuk versi PDF .)
Ketiga: Sifat dinamis Javascript memiliki pengaruh yang jauh lebih besar daripada jenis warisan. Fakta bahwa saya dapat menambahkan metode baru ke semua instance dari suatu jenis dengan menetapkannya ke objek dasar rapi, tapi saya bisa melakukan hal yang sama di Ruby, dengan membuka kembali kelas.
Keempat: Perbedaan praktisnya kecil, sementara masalah praktis lupa menggunakan
new
jauh lebih besar - yaitu, Anda jauh lebih mungkin terpengaruh oleh kehilangan nilainew
daripada Anda akan terpengaruh oleh perbedaan antara kode prototipe dan kode klasik .Semua yang mengatakan, perbedaan praktis antara pewarisan prototypal dan klasik adalah bahwa hal-hal Anda-yang-tahan-metode (kelas) adalah sama dengan hal-hal-yang-tahan-data Anda (contoh.) Ini berarti bahwa Anda dapat membangun kelas Anda sedikit demi sedikit, menggunakan semua alat manipulasi objek yang sama yang akan Anda gunakan pada contoh apa pun. (Ini, pada kenyataannya, bagaimana semua perpustakaan emulasi kelas melakukannya. Untuk pendekatan yang tidak terlalu seperti semua yang lain, lihat Traits.js ). Ini terutama menarik jika Anda metaprogramming.
sumber
Warisan prototipe dalam JavaScript berbeda dari kelas dalam cara-cara penting ini:
Konstruktor hanyalah fungsi yang dapat Anda panggil tanpa
new
:Tidak ada variabel atau metode pribadi, yang terbaik Anda dapat melakukan ini:
Dalam contoh sebelumnya, Anda tidak dapat memperluas kelas secara bermakna jika Anda menggunakan variabel dan metode pribadi palsu dan sebagai tambahan metode publik apa pun yang telah Anda nyatakan akan dibuat ulang setiap kali instance baru dibuat.
sumber
color
,r
,x
,y
dandrawCircle
yang terikat pada lingkup leksikalCircle
Circle.call()
sebagai konstruktor? Sepertinya Anda mencoba menggambarkan "objek fungsional" (keliru ...)