Beberapa pro dan kontra
Pro untuk polimorfik:
- Antarmuka polimorfik yang lebih kecil lebih mudah dibaca. Saya hanya perlu mengingat satu metode.
- Ini sesuai dengan cara bahasa dimaksudkan untuk digunakan - Mengetik bebek.
- Jika jelas objek mana yang ingin saya tarik keluar kelinci, seharusnya tidak ada ambiguitas.
- Melakukan banyak pengecekan tipe dianggap buruk bahkan dalam bahasa statis seperti Java, di mana memiliki banyak pengecekan tipe untuk jenis objek membuat kode jelek, jika penyihir benar-benar perlu membedakan antara jenis objek yang ia tarik keluar kelinci dari ?
Pro untuk ad-hoc:
- Itu kurang eksplisit, bisakah saya menarik string dari
Cat
instance? Apakah itu hanya berfungsi? jika tidak, apa perilakunya? Jika saya tidak membatasi jenis di sini, saya harus melakukannya dalam dokumentasi, atau dalam tes yang mungkin membuat kontrak lebih buruk.
- Anda memiliki semua penanganan menarik kelinci di satu tempat, si Penyihir (beberapa mungkin menganggap ini penipu)
- Pengoptimal JS modern membedakan antara fungsi monomorfik (hanya bekerja pada satu tipe) dan polimorfik. Mereka tahu cara mengoptimalkan yang monomorfik jauh lebih baik sehingga
pullRabbitOutOfString
versi ini kemungkinan akan jauh lebih cepat di mesin seperti V8. Lihat video ini untuk informasi lebih lanjut. Sunting: Saya menulis perf, ternyata dalam prakteknya, ini tidak selalu terjadi .
Beberapa solusi alternatif:
Menurut pendapat saya, desain semacam ini tidak terlalu 'Java-Scripty' untuk memulai. JavaScript adalah bahasa yang berbeda dengan idiom yang berbeda dari bahasa seperti C #, Java atau Python. Idiom-idiom ini berasal dari pengembang bertahun-tahun yang mencoba memahami bagian bahasa yang lemah dan kuat, yang saya lakukan adalah mencoba untuk tetap menggunakan idiom-idiom ini.
Ada dua solusi bagus yang dapat saya pikirkan:
- Mengangkat objek, membuat objek "menarik", membuatnya sesuai dengan antarmuka saat run-time, kemudian meminta Magician bekerja pada objek yang dapat ditarik.
- Menggunakan pola strategi, mengajar Pesulap secara dinamis bagaimana menangani berbagai jenis objek.
Solusi 1: Mengangkat Objek
Salah satu solusi umum untuk masalah ini, adalah 'meninggikan' benda dengan kemampuan kelinci ditarik keluar.
Artinya, memiliki fungsi yang mengambil beberapa jenis objek, dan menambahkan menarik topi untuk itu. Sesuatu seperti:
function makePullable(obj){
obj.pullOfHat = function(){
return new Rabbit(obj.toString());
}
}
Saya dapat membuat makePullable
fungsi seperti itu untuk objek lain, saya bisa membuat makePullableString
, dll. Saya mendefinisikan konversi pada setiap jenis. Namun, setelah saya mengangkat objek saya, saya tidak memiliki tipe untuk menggunakannya secara umum. Antarmuka dalam JavaScript ditentukan oleh mengetik bebek, jika memiliki pullOfHat
metode saya dapat menariknya dengan metode Magician.
Kemudian Magician bisa melakukan:
Magician.pullRabbit = function(pullable) {
var rabbit = obj.pullOfHat();
return {rabbit:rabbit,text:"Tada, I pulled a rabbit out of "+pullable};
}
Mengangkat objek, menggunakan semacam pola mixin sepertinya lebih banyak hal JS yang harus dilakukan. (Catatan ini bermasalah dengan tipe nilai dalam bahasa yang berupa string, angka, null, tidak terdefinisi dan boolean, tetapi semuanya bisa dilakukan dalam kotak)
Berikut adalah contoh dari apa yang terlihat seperti kode
Solusi 2: Pola Strategi
Ketika mendiskusikan pertanyaan ini di ruang obrolan JS di StackOverflow, teman saya phenomnomnominal menyarankan penggunaan pola Strategi .
Ini akan memungkinkan Anda untuk menambahkan kemampuan untuk menarik kelinci keluar dari berbagai objek pada saat dijalankan, dan akan membuat kode yang sangat JavaScript. Seorang pesulap dapat belajar cara menarik benda-benda dari berbagai jenis dari topi, dan itu menarik mereka berdasarkan pengetahuan itu.
Berikut ini tampilannya di CoffeeScript:
class Magician
constructor: ()-> # A new Magician can't pull anything
@pullFunctions = {}
pullRabbit: (obj) -> # Pull a rabbit, handler based on type
func = pullFunctions[obj.constructor.name]
if func? then func(obj) else "Don't know how to pull that out of my hat!"
learnToPull: (obj, handler) -> # Learns to pull a rabbit out of a type
pullFunctions[obj.constructor.name] = handler
Anda dapat melihat kode JS yang setara di sini .
Dengan cara ini, Anda mendapat manfaat dari kedua dunia, tindakan cara menarik tidak terlalu erat dengan objek, atau Penyihir dan saya pikir ini membuat solusi yang sangat bagus.
Penggunaan akan menjadi seperti:
var m = new Magician();//create a new Magician
//Teach the Magician
m.learnToPull("",function(){
return "Pulled a rabbit out of a string";
});
m.learnToPull({},function(){
return "Pulled a rabbit out of a Object";
});
m.pullRabbit(" Str");