Saya cukup akrab dengan kapan harus menggunakan subclass dan modul, tetapi baru-baru ini saya telah melihat kelas bersarang seperti ini:
class Foo
class Bar
# do some useful things
end
end
Serta kelas yang bersarang dalam modul seperti:
module Baz
class Quux
# more code
end
end
Dokumentasi dan artikel jarang atau saya tidak dididik pada subjek yang cukup untuk meraba-raba istilah pencarian yang tepat, tetapi saya sepertinya tidak dapat menemukan banyak informasi tentang topik tersebut.
Bisakah seseorang memberikan contoh atau tautan ke posting tentang mengapa / kapan teknik itu akan digunakan?
Car.new
danCar::Wheel.new
. Anda pasti tidak perlu menginisialisasiCar
objek untuk menginisialisasiCar::Wheel
objek di Ruby, tetapiCar
kelas harus dimuat dan dieksekusiCar::Wheel
agar dapat digunakan.Car
danCar::Wheel
. Modul (dan dengan demikian kelas) hanyalah ruang nama untuk konstanta, tidak ada yang namanya kelas bersarang atau modul bersarang di Ruby.Car::Wheel.new
. Ledakan. Saya baru saja membangunWheel
objek yang tidak bersarang di dalamCar
objek.Di Ruby, mendefinisikan kelas bertingkat mirip dengan mendefinisikan kelas dalam sebuah modul. Itu tidak benar-benar memaksa hubungan antara kelas, itu hanya membuat namespace untuk konstanta. (Nama Kelas dan Modul adalah konstanta.)
Jawaban yang diterima tidak benar tentang apa pun. 1 Dalam contoh di bawah ini saya membuat turunan dari kelas tertutup secara leksikal tanpa turunan dari kelas penutup yang pernah ada.
Keuntungannya sama dengan yang ada pada modul: enkapsulasi, pengelompokan kode yang hanya digunakan di satu tempat, dan menempatkan kode lebih dekat ke tempat digunakannya. Proyek besar mungkin memiliki satu modul luar yang terjadi berulang-ulang di setiap file sumber dan berisi banyak definisi kelas. Ketika berbagai kerangka kerja dan kode perpustakaan semua melakukan ini, maka mereka hanya berkontribusi satu nama masing-masing ke tingkat atas, mengurangi kemungkinan konflik. Prosa, tentu saja, tapi itu sebabnya mereka digunakan.
Menggunakan kelas alih-alih modul untuk mendefinisikan namespace luar mungkin masuk akal dalam program atau skrip satu file, atau jika Anda sudah menggunakan kelas tingkat atas untuk sesuatu, atau jika Anda benar-benar akan menambahkan kode untuk menghubungkan kelas bersama-sama dalam gaya kelas batin sejati . Ruby tidak memiliki kelas dalam tetapi tidak ada yang menghentikan Anda untuk membuat perilaku yang sama dalam kode. Merujuk objek luar dari yang dalam masih akan membutuhkan titik-titik dari instance objek luar tetapi kelas bersarang akan menyarankan bahwa ini adalah apa yang mungkin Anda lakukan. Program termodulasi dengan hati-hati mungkin selalu membuat kelas-kelas yang melampirkan terlebih dahulu, dan mereka mungkin cukup didekomposisi dengan kelas bersarang atau batin. Anda tidak dapat memanggil
new
modul.Anda dapat menggunakan pola umum bahkan untuk skrip, di mana namespace tidak terlalu dibutuhkan, hanya untuk bersenang-senang dan berlatih ...
sumber
B
ini tidak dalam kelasA
. The konstanB
-namespace dalam kelasA
, tapi sama sekali tidak ada hubungan antara objek direferensikan olehB
(yang dalam hal ini hanya terjadi menjadi kelas) dan kelas direferensikan olehA
.You can't call new on a module.
- jadi dalam istilah dasar jika saya hanya ingin namespace beberapa kelas dan tidak perlu benar-benar membuat turunan dari "kelas" luar, maka Saya akan menggunakan modul luar. Tetapi jika saya ingin instantiate instance dari "kelas" pembungkus / luar maka saya akan membuatnya menjadi Kelas bukan Modul. Setidaknya ini masuk akal bagi saya.Anda mungkin ingin menggunakan ini untuk mengelompokkan kelas Anda ke dalam modul. Semacam hal namespace.
misalnya permata Twitter menggunakan ruang nama untuk mencapai ini:
Jadi keduanya
Client
danSearch
kelas hidup di bawahTwitter
modul.Jika Anda ingin memeriksa sumbernya, kode untuk kedua kelas dapat ditemukan di sini dan di sini .
Semoga ini membantu!
sumber
Ada perbedaan lain antara kelas bersarang dan modul bersarang di Ruby sebelum 2,5 yang jawaban lain gagal untuk menutupi yang saya rasa harus disebutkan di sini. Ini adalah proses pencarian.
Singkatnya: karena pencarian konstan tingkat atas di Ruby sebelum 2.5, Ruby mungkin akhirnya mencari kelas bersarang Anda di tempat yang salah (
Object
khususnya) jika Anda menggunakan kelas bersarang.Di Ruby sebelum 2.5:
Struktur kelas bersarang: Misalkan Anda memiliki kelas
X
, dengan kelas bertingkatY
, atauX::Y
. Dan kemudian Anda memiliki kelas tingkat atas bernama jugaY
. JikaX::Y
tidak dimuat, maka hal berikut terjadi ketika Anda meneleponX::Y
:Setelah tidak ditemukan
Y
diX
, Ruby akan mencoba untuk mencarinya di nenek moyangX
. SejakX
adalah kelas dan bukan modul, ia memiliki leluhur, di antaranya adalah[Object, Kernel, BasicObject]
. Jadi, ia mencoba mencari ,Y
diObject
mana ia berhasil menemukannya.Namun itu adalah level atas
Y
dan bukanX::Y
. Anda akan mendapatkan peringatan ini:Struktur modul bersarang: Misalkan pada contoh sebelumnya
X
adalah modul dan bukan kelas.Modul hanya memiliki dirinya sebagai leluhur:
X.ancestors
akan menghasilkan[X]
.Dalam hal ini, Ruby tidak akan dapat mencari
Y
di salah satu leluhurX
dan akan melemparNameError
. Rails (atau kerangka kerja lainnya dengan autoloading) akan mencoba memuatX::Y
setelah itu.Lihat artikel ini untuk informasi lebih lanjut: https://blog.jetbrains.com/ruby/2017/03/why-you-should-not-use-a--class-as-a-namespace-in-rails-applications/
In Ruby 2.5:
Pencarian konstan tingkat atas dihapus.
Anda dapat menggunakan kelas bersarang tanpa takut menemukan bug ini.
sumber
Selain jawaban sebelumnya: Modul di Ruby adalah kelas
sumber
new
. Jadi meskipun Anda dapat mengatakan Modul adalah kelas (huruf kecil), mereka tidak sama dengan Kelas (huruf besar) :)