Saya tahu tidak ada konsep kelas abstrak di ruby. Tetapi jika memang perlu diterapkan, bagaimana cara melakukannya? Saya mencoba sesuatu seperti ...
class A
def self.new
raise 'Doh! You are trying to write Java in Ruby!'
end
end
class B < A
...
...
end
Tetapi ketika saya mencoba untuk membuat instance B, itu secara internal akan memanggil A.new
yang akan memunculkan pengecualian.
Selain itu, modul tidak dapat dibuat instance-nya tetapi juga tidak dapat diwariskan. membuat metode baru menjadi pribadi juga tidak akan berfungsi. Ada petunjuk?
ruby
abstract-class
Chirantan
sumber
sumber
raise "Doh! You are trying to write Java in Ruby"
.Jawaban:
Saya tidak suka menggunakan kelas abstrak di Ruby (hampir selalu ada cara yang lebih baik). Namun, jika menurut Anda ini adalah teknik terbaik untuk situasi tersebut, Anda dapat menggunakan cuplikan berikut agar lebih deklaratif tentang metode mana yang abstrak:
Pada dasarnya, Anda hanya memanggil
abstract_methods
dengan daftar metode yang abstrak, dan ketika dipanggil oleh instance kelas abstrak,NotImplementedError
pengecualian akan dimunculkan.sumber
NotImplementedError
yang pada dasarnya berarti "bergantung pada platform, tidak tersedia untuk Anda". Lihat dokumen .Hanya untuk berpadu di sini, saya pikir tidak ada alasan untuk menghentikan seseorang dari membuat instance kelas abstrak, terutama karena mereka dapat menambahkan metode ke dalamnya dengan cepat .
Bahasa pengetikan bebek, seperti Ruby, menggunakan keberadaan / ketidakhadiran atau perilaku metode pada waktu proses untuk menentukan apakah mereka harus dipanggil atau tidak. Oleh karena itu, pertanyaan Anda, karena berlaku untuk metode abstrak , masuk akal
dan itu seharusnya tentang akhir cerita. Satu-satunya alasan untuk menggunakan kelas abstrak di Java adalah untuk menegaskan bahwa metode tertentu "diisi" sementara yang lain memiliki perilakunya di kelas abstrak. Dalam bahasa pengetikan bebek, fokusnya adalah pada metode, bukan pada kelas / tipe, jadi Anda harus memindahkan kekhawatiran Anda ke level itu.
Dalam pertanyaan Anda, pada dasarnya Anda mencoba membuat ulang
abstract
kata kunci dari Java, yang merupakan code-bau untuk melakukan Java di Ruby.sumber
Coba ini:
sumber
#initialize
B, Anda sebenarnya dapat meningkatkan apa pun di A # inisialisasiif self.class == A
.sumber
untuk siapa saja di dunia rails, mengimplementasikan model ActiveRecord sebagai kelas abstrak dilakukan dengan deklarasi ini di file model:
sumber
2 ¢ saya: Saya memilih mixin DSL yang sederhana dan ringan:
Dan, tentu saja, menambahkan kesalahan lain untuk menginisialisasi kelas dasar akan menjadi hal yang sepele dalam kasus ini.
sumber
err = NotImplementedError.new(message); err.set_backtrace caller()
YMMVDalam 6 1/2 tahun terakhir pemrograman Ruby, saya tidak membutuhkannya kelas abstrak sekali pun.
Jika Anda berpikir Anda membutuhkan kelas abstrak, Anda berpikir terlalu banyak dalam bahasa yang menyediakan / membutuhkannya, bukan di Ruby.
Seperti yang disarankan orang lain, mixin lebih sesuai untuk hal-hal yang seharusnya menjadi antarmuka (seperti yang didefinisikan oleh Java), dan memikirkan kembali desain Anda lebih tepat untuk hal-hal yang "membutuhkan" kelas abstrak dari bahasa lain seperti C ++.
Pembaruan 2019: Saya tidak membutuhkan kelas abstrak di Ruby selama 16½ tahun penggunaan. Segala sesuatu yang dikatakan oleh semua orang yang mengomentari tanggapan saya ditangani dengan benar-benar mempelajari Ruby dan menggunakan alat yang sesuai, seperti modul (yang bahkan memberi Anda implementasi umum). Ada orang-orang di tim yang saya kelola yang telah membuat kelas yang memiliki implementasi dasar yang gagal (seperti kelas abstrak), tetapi ini sebagian besar adalah pemborosan kode karena
NoMethodError
akan menghasilkan hasil yang sama persis denganAbstractClassError
produksi.sumber
Anda dapat mencoba 3 rubygems:
interface
abstract
simple abstract
sumber
Secara pribadi saya mengangkat NotImplementedError dalam metode kelas abstrak. Tetapi Anda mungkin ingin meninggalkannya dari metode 'baru', karena alasan yang Anda sebutkan.
sumber
initialize
metode ruby, orang tua tidak dipanggil secara otomatis kecuali secara eksplisit dipanggil dengan super.Jika Anda ingin menggunakan kelas uninstantiable, dalam metode A.new Anda, periksa apakah self == A sebelum melakukan kesalahan.
Tapi sungguh, modul tampaknya lebih seperti yang Anda inginkan di sini - misalnya, Enumerable adalah jenis yang mungkin menjadi kelas abstrak dalam bahasa lain. Anda secara teknis tidak dapat membuat subkelasnya, tetapi panggilan
include SomeModule
mencapai tujuan yang kira-kira sama. Apakah ada alasan mengapa ini tidak berhasil untuk Anda?sumber
Tujuan apa yang Anda coba layani dengan kelas abstrak? Mungkin ada cara yang lebih baik untuk melakukannya di ruby, tetapi Anda tidak memberikan detailnya.
Pointer saya adalah ini; gunakan mixin bukan warisan.
sumber
Jawaban lain:
Ini bergantung pada #method_missing normal untuk melaporkan metode yang tidak diterapkan, tetapi mencegah kelas abstrak diterapkan (bahkan jika mereka memiliki metode inisialisasi)
Seperti yang dikatakan poster lain, Anda mungkin harus menggunakan mixin, daripada kelas abstrak.
sumber
Saya melakukannya dengan cara ini, sehingga mendefinisikan baru pada kelas anak untuk menemukan yang baru pada kelas non abstrak. Saya masih tidak melihat ada praktik praktis dalam menggunakan kelas abstrak di ruby.
sumber
Ada juga yang kecil ini
abstract_type
permata , memungkinkan untuk mendeklarasikan kelas dan modul abstrak dengan cara yang tidak mengganggu.Contoh (dari file README.md ):
sumber
Tidak ada yang salah dengan pendekatan Anda. Menaikkan kesalahan dalam menginisialisasi tampaknya baik-baik saja, selama tentu saja semua subkelas Anda menimpa inisialisasi. Tetapi Anda tidak ingin mendefinisikan diri sendiri. Baru seperti itu. Inilah yang akan saya lakukan.
Pendekatan lain akan meletakkan semua fungsionalitas itu dalam sebuah modul, yang seperti yang Anda sebutkan tidak akan pernah dapat diinstiasi. Kemudian sertakan modul di kelas Anda daripada mewarisi dari kelas lain. Namun, ini akan merusak hal-hal seperti super.
Jadi itu tergantung pada bagaimana Anda ingin menyusunnya. Meskipun modul tampak seperti solusi yang lebih bersih untuk memecahkan masalah "Bagaimana cara menulis beberapa hal yang berkenan digunakan kelas lain"
sumber
Permata 2 baris: https://rubygems.org/gems/abstract
sumber
Meskipun ini tidak terasa seperti Ruby, Anda dapat melakukan ini:
Hasil:
sumber