Saya tahu ini sepertinya pertanyaan aneh, karena titik dua atau lebih objek berbagi kelas yang sama adalah bahwa perilaku mereka sama, yaitu metode mereka identik.
Namun, saya ingin tahu apakah ada bahasa OOP yang memungkinkan Anda untuk mendefinisikan kembali metode objek dengan cara yang sama seperti Anda dapat menetapkan nilai yang berbeda untuk bidangnya. Hasilnya adalah objek yang dibangun dari kelas yang sama tidak lagi menunjukkan perilaku yang sama persis.
Jika saya tidak salah, Anda dapat melakukan ini JavaScript? Seiring dengan pertanyaan ini, saya bertanya, mengapa seseorang ingin melakukan ini?
object-oriented
programming-languages
Niko Bellic
sumber
sumber
setClickHandler()
metode dan membuat contoh berbeda dari kelas yang sama melakukan hal yang sangat berbeda. Dalam bahasa yang tidak memiliki ekspresi lambda yang nyaman, lebih mudah untuk membuat subkelas anonim baru hanya untuk penangan baru. Secara tradisional, metode utama dianggap sebagai ciri khas kelas baru , sementara pengaturan nilai atribut tidak, tetapi terutama dengan fungsi handler, keduanya memiliki efek yang sangat mirip, sehingga perbedaan menjadi perang tentang kata-kata.Jawaban:
Metode dalam sebagian besar bahasa OOP (berbasis kelas) ditetapkan berdasarkan jenis.
JavaScript adalah berbasis prototipe, bukan berbasis kelas sehingga Anda dapat mengganti metode pada basis per-instance karena tidak ada perbedaan yang sulit antara "kelas" dan objek; pada kenyataannya, "kelas" dalam JavaScript adalah objek yang seperti templat untuk bagaimana instance harus bekerja.
Bahasa apa pun yang memungkinkan fungsi kelas satu, Scala, Java 8, C # (via delegate) dll, dapat bertindak seperti Anda memiliki metode per-instance override; Anda harus mendefinisikan bidang dengan tipe fungsi dan kemudian menimpanya di setiap instance.
Scala memiliki kemungkinan lain; Di Scala, Anda bisa membuat objek lajang (menggunakan kata kunci objek alih-alih kata kunci kelas), sehingga Anda dapat memperluas kelas Anda dan menimpa metode, menghasilkan contoh baru dari kelas dasar dengan override.
Mengapa seseorang melakukan ini? Mungkin ada lusinan alasan. Mungkin saja perilaku itu perlu saya definisikan lebih ketat daripada menggunakan berbagai kombinasi bidang. Itu juga bisa menjaga kode dipisahkan dan diatur lebih baik. Namun secara umum, saya pikir kasus ini lebih jarang dan sering ada solusi yang lebih mudah menggunakan nilai-nilai bidang.
sumber
Sulit untuk menebak motivasi untuk pertanyaan Anda, dan karena itu beberapa kemungkinan jawaban mungkin atau mungkin tidak menjawab minat Anda yang sebenarnya.
Bahkan dalam beberapa bahasa non-prototipe dimungkinkan untuk memperkirakan efek ini.
Di Jawa, misalnya, kelas dalam anonim cukup dekat dengan apa yang Anda gambarkan - Anda dapat membuat dan membuat instance dari subkelas asli, menimpa hanya metode atau metode yang Anda inginkan. Kelas yang dihasilkan akan menjadi
instanceof
kelas asli, tetapi tidak akan menjadi kelas yang sama .Mengapa Anda ingin melakukan ini? Dengan ekspresi Java 8 lambda, saya pikir banyak kasus penggunaan terbaik hilang. Dengan versi Java yang lebih lama, setidaknya, ini dapat menghindari perkembangbiakan kelas-kelas sepele dan penggunaan sempit. Artinya, ketika Anda memiliki sejumlah besar kasus penggunaan terkait, berbeda hanya dalam cara fungsional kecil, Anda dapat membuatnya hampir on-the-fly (hampir), dengan perbedaan perilaku disuntikkan pada saat Anda membutuhkannya.
Yang mengatakan, bahkan sebelum J8, ini sering dapat di refactored untuk menggeser perbedaan menjadi satu atau tiga bidang, dan menyuntikkan mereka dalam konstruktor. Dengan J8, tentu saja, metode itu sendiri dapat disuntikkan ke dalam kelas, meskipun mungkin ada godaan untuk melakukannya ketika refactoring lain mungkin lebih bersih (jika tidak sedingin).
sumber
Anda meminta bahasa apa pun yang menyediakan metode per-instance. Sudah ada jawaban untuk Javascript, jadi mari kita lihat bagaimana hal itu dilakukan di Common Lisp, di mana Anda dapat menggunakan spesialis-EQL:
Mengapa?
EQL-specializers berguna ketika argumen subjek pengiriman seharusnya memiliki tipe yang
eql
masuk akal: angka, simbol, dll. Secara umum, Anda tidak memerlukannya, dan Anda hanya perlu mendefinisikan subclass sebanyak dibutuhkan oleh masalah Anda. Tetapi kadang-kadang, Anda hanya perlu mengirim sesuai dengan parameter yang, misalnya, simbol:case
ekspresi akan terbatas pada kasus-kasus yang diketahui dalam fungsi pengiriman, sedangkan metode dapat ditambahkan dan dihapus kapan saja.Juga, spesialisasi pada instance berguna untuk keperluan debugging, ketika Anda ingin memeriksa sementara apa yang terjadi dengan objek tertentu dalam aplikasi yang sedang berjalan.
sumber
Anda juga dapat melakukan ini di Ruby menggunakan objek tunggal:
Menghasilkan:
Sedangkan untuk penggunaan, ini sebenarnya bagaimana Ruby melakukan metode kelas dan modul. Sebagai contoh:
Sebenarnya mendefinisikan metode singleton
hello
padaClass
objekSomeClass
.sumber
extend
sebenarnya hanya menciptakan kelas singleton untuk objek dan kemudian mengimpor modul ke kelas singleton.Anda dapat menganggap metode per-instance sebagai memungkinkan Anda untuk merakit kelas Anda sendiri pada saat runtime. Ini dapat menghilangkan banyak kode lem, kode yang tidak memiliki tujuan lain selain untuk menyatukan dua kelas untuk berbicara satu sama lain. Mixin adalah solusi yang agak lebih terstruktur untuk jenis masalah yang sama.
Anda menderita sedikit dari paradoks blub , pada dasarnya sulit melihat nilai fitur bahasa sampai Anda menggunakan fitur itu dalam program nyata. Jadi, cari peluang di mana Anda pikir itu mungkin berhasil, cobalah, dan lihat apa yang terjadi.
Lihat di kode Anda untuk kelompok kelas yang hanya berbeda oleh satu metode. Cari kelas yang tujuan utamanya adalah menggabungkan dua kelas lain dalam kombinasi yang berbeda. Cari metode yang tidak melakukan apa pun selain meneruskan panggilan ke objek lain. Cari kelas yang dipakai menggunakan pola kreasi yang kompleks . Itu semua adalah kandidat potensial untuk diganti dengan metode per-instance.
sumber
Jawaban lain telah menunjukkan bagaimana ini adalah fitur umum dari bahasa berorientasi objek dinamis, dan bagaimana hal itu dapat ditiru secara sepele dalam bahasa statis yang memiliki objek fungsi kelas satu (mis. Delegasi dalam c #, objek yang menimpa operator () dalam c ++) . Dalam bahasa statis yang tidak memiliki fungsi seperti itu, ini lebih sulit, tetapi masih dapat dicapai dengan menggunakan kombinasi pola Strategi dan metode yang hanya mendelegasikan penerapannya ke strategi. Ini sebenarnya adalah hal yang sama yang akan Anda lakukan di c # dengan delegasi, tetapi sintaksnya agak berantakan.
sumber
Anda dapat melakukan hal seperti ini dalam C # dan sebagian besar bahasa serupa lainnya.
sumber
Secara konseptual, meskipun dalam bahasa seperti Java, semua instance kelas harus memiliki metode yang sama, dimungkinkan untuk membuatnya tampak seolah-olah mereka tidak dengan menambahkan lapisan tipuan tambahan, mungkin dalam kombinasi dengan kelas bersarang.
Sebagai contoh, jika sebuah kelas
Foo
dapat mendefinisikan kelas bersarang abstrak statisQuackerBase
yang berisi metodequack(Foo)
, serta beberapa kelas bersarang statis lain yang berasalQuackerBase
, masing-masing dengan definisi sendiriquack(Foo)
, maka jika kelas luar memiliki bidangquacker
tipeQuackerBase
, maka mungkin setel field itu untuk mengidentifikasi instance (mungkin tunggal) dari salah satu kelas bersarangnya. Setelah melakukannya, menjalankanquacker.quack(this)
akan mengeksekusiquack
metode kelas yang instansnya telah ditetapkan untuk bidang itu.Karena ini adalah pola yang cukup umum, Java menyertakan mekanisme untuk secara otomatis mendeklarasikan tipe yang sesuai. Mekanisme seperti itu tidak benar-benar melakukan apa pun yang tidak dapat dilakukan dengan hanya menggunakan metode virtual dan kelas statis opsional-bersarang, tetapi mereka sangat mengurangi jumlah boilerplate yang diperlukan untuk menghasilkan kelas yang tujuan utamanya adalah menjalankan metode tunggal atas nama kelas lain.
sumber
Saya percaya itu adalah definisi bahasa "Dinamis" seperti ruby, groovy & Javascript (dan Banyak Banyak Lainnya). Dynamic merujuk (setidaknya sebagian) pada kemampuan untuk secara dinamis mendefinisikan kembali bagaimana instance kelas mungkin berperilaku dengan cepat.
Ini bukan praktik OO yang hebat secara umum, tetapi bagi banyak programmer bahasa yang dinamis, prinsip-prinsip OO bukan prioritas utama mereka.
Itu menyederhanakan beberapa operasi rumit seperti Monkey-Patching di mana Anda dapat mengubah contoh kelas untuk memungkinkan Anda berinteraksi dengan perpustakaan tertutup dengan cara yang tidak mereka lihat.
sumber
Saya tidak mengatakan itu hal yang baik untuk dilakukan, tetapi ini sepele mungkin dengan Python. Saya tidak bisa menggunakan case yang baik dari atas kepala saya, tapi saya yakin mereka ada.
sumber