Hanya memusatkan kepalaku pada pemrograman Ruby. Modul / mixin selalu berhasil membingungkan saya.
- termasuk : campuran dalam metode modul yang ditentukan sebagai metode instance di kelas target
- extended : mencampur metode modul yang ditentukan sebagai metode kelas di kelas target
Jadi apakah perbedaan utama hanya ini atau apakah naga yang lebih besar mengintai? misalnya
module ReusableModule
def module_method
puts "Module Method: Hi there!"
end
end
class ClassThatIncludes
include ReusableModule
end
class ClassThatExtends
extend ReusableModule
end
puts "Include"
ClassThatIncludes.new.module_method # "Module Method: Hi there!"
puts "Extend"
ClassThatExtends.module_method # "Module Method: Hi there!"
Jawaban:
Apa yang Anda katakan itu benar. Namun ada yang lebih dari itu.
Jika Anda memiliki kelas
Klazz
dan modulMod
, termasukMod
dalamKlazz
memberikan contohKlazz
akses keMod
metode. Atau Anda dapat memperluasKlazz
denganMod
memberikan akses kelasKlazz
keMod
metode. Tetapi Anda juga dapat memperluas objek sewenang-wenango.extend Mod
. Dalam hal ini objek individu mendapatkanMod
metode meskipun semua objek lain dengan kelas yang samao
tidak.sumber
extended - menambahkan metode dan konstanta modul yang ditentukan ke metaclass target (mis. kelas singleton) misalnya
Klazz.extend(Mod)
, sekarang Klazz memiliki metode Mod (sebagai metode kelas)obj.extend(Mod)
, sekarang obj memiliki metode Mod (sebagai metode instance), tetapi tidak ada instance lain dariobj.class
metode tersebut yang ditambahkan.extend
adalah metode publiktermasuk - Secara default, ia bercampur dalam metode modul yang ditentukan sebagai metode instance dalam modul / kelas target. misalnya
class Klazz; include Mod; end;
, sekarang semua instance Klazz memiliki akses ke metode Mod (sebagai metode instance)include
adalah metode pribadi, karena ini dimaksudkan untuk dipanggil dari dalam kelas / modul wadah.Namun , modul sangat sering mengesampingkan
include
perilaku dengan cara menambal monyetincluded
. Ini sangat menonjol dalam kode Rails lama. lebih detail dari Yehuda Katz .Rincian lebih lanjut tentang
include
, dengan perilaku default-nya, dengan asumsi Anda telah menjalankan kode berikut@@foo
atau@@bar
super
Klazz # foo akan memeriksa Mod # foo sebelum memeriksa untuk metode foo superclass nyata Klazz. Lihat RubySpec untuk detailnya.).Tentu saja, dokumentasi inti ruby selalu menjadi tempat terbaik untuk hal-hal ini. Proyek RubySpec juga merupakan sumber yang fantastis, karena mereka mendokumentasikan fungsionalitasnya dengan tepat.
#include
RubySpec rubydoc#included
RubySpec rubydoc#extend
RubySpec rubydoc#extended
RubySpec rubydoc#extend_object
RubySpec rubydoc#append_features
RubySpec rubydocsumber
extend
bisa menerapkan metode sebagai metode kelas atau contoh, tergantung pada pemanfaatan.Klass.extend
= metode kelas,objekt.extend
= metode instan. Saya selalu (salah) mengasumsikan metode kelas berasalextend
, dan contoh dariinclude
.Itu benar.
Di belakang layar, termasuk sebenarnya adalah alias untuk append_features , yang (dari dokumen):
sumber
Ketika Anda
include
modul ke dalam kelas, metode modul diimpor sebagai metode contoh .Namun, ketika Anda
extend
modul ke dalam kelas, metode modul diimpor sebagai metode kelas .Sebagai contoh, jika kita memiliki modul yang
Module_test
didefinisikan sebagai berikut:Sekarang, untuk
include
modul. Jika kita mendefinisikan kelasA
sebagai berikut:Output akan:
M - in module
.Jika kita mengganti baris
include Module_test
denganextend Module_test
dan menjalankan kode lagi, kami menerima kesalahan berikut:undefined method 'func' for #<A:instance_num> (NoMethodError)
.Mengubah metode panggilan
a.func
untukA.func
, output berubah menjadi:M - in module
.Dari eksekusi kode di atas, jelas bahwa ketika kita
include
sebuah modul, metodenya menjadi metode instan dan ketika kitaextend
sebuah modul, metodenya menjadi metode kelas .sumber
Semua jawaban lain baik, termasuk tip untuk menggali melalui RubySpecs:
https://github.com/rubyspec/rubyspec/blob/master/core/module/include_spec.rb
https://github.com/rubyspec/rubyspec/blob/master/core/module/extend_object_spec.rb
Adapun kasus penggunaan:
Jika Anda menyertakan modul ReusableModule di kelas ClassThatIncludes, metode, konstanta, kelas, submodula, dan deklarasi lainnya akan direferensikan.
Jika Anda memperluas class ClassThatExtends dengan modul ReusableModule, maka metode dan konstanta akan disalin . Jelas, jika Anda tidak hati-hati, Anda dapat membuang banyak memori dengan menduplikasi definisi secara dinamis.
Jika Anda menggunakan ActiveSupport :: Concern, fungsionalitas .included () memungkinkan Anda menulis ulang kelas yang disertakan secara langsung. module ClassMethods di dalam Concern akan diperluas (disalin) ke dalam kelas yang disertakan .
sumber
Saya juga ingin menjelaskan mekanisme kerjanya. Jika saya salah, mohon koreksi.
Ketika kami menggunakan,
include
kami menambahkan tautan dari kelas kami ke modul yang berisi beberapa metode.Objek tidak memiliki metode, hanya modul dan klase yang melakukannya. Jadi ketika
a
menerima pesansome_method
itu mulai metode pencariansome_method
dia
kelas eigen, kemudian diA
kelas dan kemudian di tautkan keA
modul kelas jika ada beberapa (dalam urutan terbalik, kemenangan terakhir termasuk).Ketika kami menggunakan
extend
kami menambahkan tautan ke modul di kelas eigen objek. Jadi jika kita menggunakan A.new.extend (MyMod) kita menambahkan tautan ke modul kita ke kelas contoh eigen ataua'
kelas A. Dan jika kita menggunakan A.extend (MyMod) kita menambahkan linkage ke A (object, class juga object) eigenclassA'
.jadi jalur pencarian metode
a
adalah sebagai berikut: a => a '=> modul tertaut ke a' class => A.juga ada metode prepend yang mengubah jalur pencarian:
a => a '=> modul bergantung pada A => A => termasuk modul ke A
maaf untuk bahasa inggris saya yang buruk.
sumber