Variabel instance pada kelas:
class Parent
@things = []
def self.things
@things
end
def things
self.class.things
end
end
class Child < Parent
@things = []
end
Parent.things << :car
Child.things << :doll
mom = Parent.new
dad = Parent.new
p Parent.things #=> [:car]
p Child.things #=> [:doll]
p mom.things #=> [:car]
p dad.things #=> [:car]
Variabel kelas:
class Parent
@@things = []
def self.things
@@things
end
def things
@@things
end
end
class Child < Parent
end
Parent.things << :car
Child.things << :doll
p Parent.things #=> [:car,:doll]
p Child.things #=> [:car,:doll]
mom = Parent.new
dad = Parent.new
son1 = Child.new
son2 = Child.new
daughter = Child.new
[ mom, dad, son1, son2, daughter ].each{ |person| p person.things }
#=> [:car, :doll]
#=> [:car, :doll]
#=> [:car, :doll]
#=> [:car, :doll]
#=> [:car, :doll]
Dengan variabel instan pada kelas (bukan pada instance kelas itu) Anda dapat menyimpan sesuatu yang umum untuk kelas itu tanpa memiliki sub-kelas secara otomatis juga mendapatkannya (dan sebaliknya). Dengan variabel kelas, Anda memiliki kemudahan untuk tidak harus menulis self.class
dari objek instan, dan (bila diinginkan) Anda juga mendapatkan pembagian otomatis di seluruh hierarki kelas.
Menggabungkan ini bersama-sama menjadi satu contoh yang juga mencakup variabel instan pada instance:
class Parent
@@family_things = [] # Shared between class and subclasses
@shared_things = [] # Specific to this class
def self.family_things
@@family_things
end
def self.shared_things
@shared_things
end
attr_accessor :my_things
def initialize
@my_things = [] # Just for me
end
def family_things
self.class.family_things
end
def shared_things
self.class.shared_things
end
end
class Child < Parent
@shared_things = []
end
Dan kemudian beraksi:
mama = Parent.new
papa = Parent.new
joey = Child.new
suzy = Child.new
Parent.family_things << :house
papa.family_things << :vacuum
mama.shared_things << :car
papa.shared_things << :blender
papa.my_things << :quadcopter
joey.my_things << :bike
suzy.my_things << :doll
joey.shared_things << :puzzle
suzy.shared_things << :blocks
p Parent.family_things #=> [:house, :vacuum]
p Child.family_things #=> [:house, :vacuum]
p papa.family_things #=> [:house, :vacuum]
p mama.family_things #=> [:house, :vacuum]
p joey.family_things #=> [:house, :vacuum]
p suzy.family_things #=> [:house, :vacuum]
p Parent.shared_things #=> [:car, :blender]
p papa.shared_things #=> [:car, :blender]
p mama.shared_things #=> [:car, :blender]
p Child.shared_things #=> [:puzzle, :blocks]
p joey.shared_things #=> [:puzzle, :blocks]
p suzy.shared_things #=> [:puzzle, :blocks]
p papa.my_things #=> [:quadcopter]
p mama.my_things #=> []
p joey.my_things #=> [:bike]
p suzy.my_things #=> [:doll]
self.things
mereferensikan metodethings
dalam lingkup saat ini (dalam hal instance kelas, itu akan menjadi metode instance), di manaself.class.things
referensithings
metode dari kelas lingkup saat ini (sekali lagi dalam kasus instance dari kelas itu berarti metode kelas).Saya percaya perbedaan utama (hanya?) Adalah warisan:
Variabel kelas dibagi oleh semua "instance kelas" (yaitu subclass), sedangkan variabel instance kelas hanya khusus untuk kelas itu. Tetapi jika Anda tidak pernah berniat untuk memperpanjang kelas Anda, perbedaannya adalah murni akademis.
sumber
S.new.s => nil
danS.new.k => 23
.Sumber
Ketersediaan untuk metode instan
Warisan
sumber
Seperti yang dikatakan orang lain, variabel kelas dibagi antara kelas yang diberikan dan subkelasnya. Variabel instance kelas milik tepat satu kelas; subkelasnya terpisah.
Mengapa perilaku ini ada? Ya, semua yang ada di Ruby adalah objek — bahkan kelas. Itu berarti bahwa setiap kelas memiliki objek kelas
Class
(atau lebih tepatnya, subkelasClass
) yang sesuai dengannya. (Ketika Anda mengatakanclass Foo
, Anda benar-benar mendeklarasikan konstantaFoo
dan menetapkan objek kelas untuk itu.) Dan setiap objek Ruby dapat memiliki variabel instan, jadi objek kelas dapat memiliki variabel instan juga.Masalahnya adalah, variabel instan pada objek kelas tidak benar-benar berperilaku seperti biasanya Anda ingin variabel kelas berperilaku. Anda biasanya ingin variabel kelas yang didefinisikan dalam superclass untuk dibagikan dengan subkelasnya, tetapi bukan itu cara variabel instan bekerja — subkelas memiliki objek kelasnya sendiri, dan objek kelas itu memiliki variabel turunannya sendiri. Jadi mereka memperkenalkan variabel kelas terpisah dengan perilaku yang lebih Anda inginkan.
Dengan kata lain, variabel instance kelas adalah semacam kecelakaan desain Ruby. Anda mungkin tidak boleh menggunakannya kecuali Anda secara khusus tahu itu yang Anda cari.
sumber
FAQ Ruby Resmi: Apa perbedaan antara variabel kelas dan variabel instance kelas?
Perbedaan utama adalah perilaku mengenai pewarisan: variabel kelas dibagi antara kelas dan semua subkelasnya, sementara variabel instance kelas hanya milik satu kelas tertentu.
Variabel kelas dalam beberapa cara dapat dilihat sebagai variabel global dalam konteks hierarki warisan, dengan semua masalah yang datang dengan variabel global. Sebagai contoh, variabel kelas mungkin (secara tidak sengaja) dipindahkan oleh salah satu subkelasnya, yang memengaruhi semua kelas lainnya:
Atau, suatu kelas leluhur mungkin kemudian dibuka kembali dan diubah, dengan kemungkinan efek mengejutkan:
Jadi, kecuali Anda tahu persis apa yang Anda lakukan dan secara eksplisit membutuhkan perilaku semacam ini, Anda sebaiknya menggunakan variabel instance kelas.
sumber
Bagi mereka yang memiliki latar belakang C ++, Anda mungkin tertarik dalam perbandingan dengan setara C ++:
Seperti yang bisa kita lihat,
k
adalahstatic
variabel like. Ini 100% seperti variabel global, kecuali bahwa itu dimiliki oleh kelas ( dicakup untuk menjadi benar). Ini membuatnya lebih mudah untuk menghindari perselisihan antara variabel yang bernama sama. Seperti variabel global apa pun, hanya ada satu instance dari variabel itu dan memodifikasinya selalu terlihat oleh semua.Di sisi lain,
s
adalah nilai spesifik objek. Setiap objek memiliki nilai instansinya sendiri. Di C ++, Anda harus membuat instance untuk memiliki akses ke variabel itu. Di Ruby, definisi kelas itu sendiri adalah turunan dari kelas (dalam JavaScript, ini disebut prototipe), oleh karena itu Anda dapat mengaksess
dari kelas tanpa instantiasi tambahan. Instance kelas dapat dimodifikasi, tetapi modifikasis
akan spesifik untuk setiap instance (setiap objek tipeS
). Jadi memodifikasi satu tidak akan mengubah nilai yang lain.sumber
Meskipun mungkin langsung bermanfaat untuk menggunakan variabel instance kelas, karena variabel instance kelas dibagi di antara subclass dan mereka dapat dirujuk dalam metode singleton dan instance, ada kelemahannya. Mereka dibagikan dan subclass dapat mengubah nilai variabel instance kelas, dan kelas dasar juga akan dipengaruhi oleh perubahan, yang biasanya merupakan perilaku yang tidak diinginkan:
Rails memperkenalkan metode praktis yang disebut class_attribute. Seperti namanya, itu menyatakan atribut tingkat kelas yang nilainya diturunkan oleh subclass. Nilai class_attribute dapat diakses dalam metode singleton dan instance, seperti halnya dengan variabel instance kelas. Namun, manfaat besar dengan class_attribute di Rails adalah subclass dapat mengubah nilainya sendiri dan tidak akan memengaruhi kelas induk.
sumber
self.
setiap kali Anda ingin mengakses atributc
, misalnyaself.c
. Dokumen mengatakan suatudefault:
parameter dapat diteruskanclass_attribute
tetapi tampaknya tidak berfungsi karena poin yang baru saja saya sebutkanself
.