programacion - ruby on rails poo
Variable de instancia de clase Ruby vs. variable de clase (4)
Como dijeron otros, las variables de clase se comparten entre una clase determinada y sus subclases. Las variables de instancia de clase pertenecen exactamente a una clase; sus subclases están separadas.
¿Por qué existe este comportamiento? Bueno, todo en Ruby es un objeto, incluso clases. Eso significa que cada clase tiene un objeto de la clase Class
(o más bien, una subclase de Class
) que le corresponde. (Cuando dices class Foo
, estás declarando realmente un Foo
constante y asignándole un objeto de clase.) Y cada objeto Ruby puede tener variables de instancia, de modo que los objetos de clase también pueden tener variables de instancia.
El problema es que las variables de instancia en los objetos de la clase no se comportan realmente de la manera en que normalmente queremos que se comporten las variables de la clase. Por lo general, desea que una variable de clase definida en una superclase se comparta con sus subclases, pero no es así como funcionan las variables de instancia: la subclase tiene su propio objeto de clase y ese objeto de clase tiene sus propias variables de instancia. Entonces introdujeron variables de clase separadas con el comportamiento que es más probable que desee.
En otras palabras, las variables de instancia de clase son una especie de accidente del diseño de Ruby. Probablemente no deberías usarlos a menos que sepas específicamente que son lo que estás buscando.
Leí "¿ Cuándo se configuran las variables de instancia de Ruby? ", Pero me da mucho miedo cuándo utilizar las variables de instancia de la clase.
Las variables de clase son compartidas por todos los objetos de una clase, las variables de instancia pertenecen a un objeto. No queda mucho espacio para usar variables de instancia de clase si tenemos variables de clase.
¿Podría alguien explicar la diferencia entre estos dos y cuándo usarlos?
Aquí hay un ejemplo de código:
class S
@@k = 23
@s = 15
def self.s
@s
end
def self.k
@@k
end
end
p S.s #15
p S.k #23
Ahora entiendo, las variables de instancia de clase no se pasan a lo largo de la cadena de herencia.
Creo que el principal (¿solo?) Diferente es la herencia:
class T < S
end
p T.k
=> 23
S.k = 24
p T.k
=> 24
p T.s
=> nil
Las variables de clase son compartidas por todas las "instancias de clase" (es decir, subclases), mientras que las variables de instancia de clase son específicas solo de esa clase. Pero si nunca intenta extender su clase, la diferencia es puramente académica.
La variable de instancia de clase # está disponible solo para el método de clase y no para los métodos de instancia mientras que las variables de clase están disponibles tanto para los métodos de instancia como para los métodos de clase. Además, las variables de instancia de clase se pierden en la cadena de herencia, mientras que las variables de clase no lo son.
class Vars
@class_ins_var = "class instance variable value" #class instance variable
@@class_var = "class variable value" #class variable
def self.class_method
puts @class_ins_var
puts @@class_var
end
def instance_method
puts @class_ins_var
puts @@class_var
end
end
Vars.class_method
puts "see the difference"
obj = Vars.new
obj.instance_method
class VarsChild < Vars
end
VarsChild.class_method
Variable de instancia en una clase:
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]
Variable de clase:
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]
Con una variable de instancia en una clase (no en una instancia de esa clase) puede almacenar algo común para esa clase sin tener subclases que también las obtenga automáticamente (y viceversa). Con las variables de clase, tiene la comodidad de no tener que escribir self.class
desde un objeto de instancia, y (cuando sea conveniente) también obtiene compartir automáticamente en toda la jerarquía de clases.
Fusionando estos juntos en un solo ejemplo que también cubre variables de instancia en instancias:
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
Y luego en acción:
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]