2012-02-16 52 views
35

Soy muy nuevo en ruby ​​(en realidad soy desarrollador C#), por lo que esta pregunta podría ser novata. Tengo una clase como la siguiente, y utilicé variables de instancia (matriz) para evitar el uso de muchos parámetros de método.Uso de variables de instancia en métodos de clase - Ruby

Funciona como esperaba pero ¿es una buena práctica? En realidad, no esperaría que funcionara, pero supongo que los métodos de clase no funcionan como métodos estáticos en otros idiomas, entonces me pregunto si es una buena práctica o si puedo enfrentar problemas tales como actuar esas variables como variables de clase y arruinando todo.

class DummyClass 
    def self.dummy_method1 
    @arr = [] 
    # Play with that array 
    end 

    def self.dummy_method2 
    # use @arr for something else 
    end 
end 

Respuesta

58

La razón variables de instancia de trabajo en clases en Ruby es que las clases de Ruby son casos propios (instancias de la clase Class). Pruébelo usted mismo inspeccionando DummyClass.class. No hay "métodos estáticos" en el sentido de C# en Ruby porque cada método se define en (o se hereda) en alguna instancia y se invoca en alguna instancia. En consecuencia, pueden acceder a cualquier variable de instancia que esté disponible en el destinatario.

Dado que DummyClass es una instancia, puede tener sus propias variables de instancia muy bien. Incluso puede acceder a esas variables de instancia siempre que tenga una referencia a la clase (que siempre debe ser porque los nombres de las clases son constantes). En cualquier punto, podrá llamar al ::DummyClass.instance_variable_get(:@arr) y obtener el valor actual de esa variable de instancia.

En cuanto a si es una buena cosa hacer, depende de los métodos.

Si @arr es lógicamente el "estado" de la instancia/clase DummyClass, guárdelo en la variable de instancia. Si @arr solo se usa en dummy_method2 como acceso directo operativo, páselo como argumento. Para dar un ejemplo donde se usa el enfoque de variable de instancia, considere ActiveRecord in Rails. Se le permite hacer esto:

u = User.new 
u.name = "foobar" 
u.save 

Aquí, el nombre que se ha asignado al usuario es un dato que es legítimamente en el usuario. Si, antes de la llamada #save, uno fuera a preguntar "¿cuál es el nombre del usuario en este punto", respondería "foobar". Si profundiza lo suficiente en las partes internas (excavará muy lejos y en una gran cantidad de metaprogramación, encontrará que utilizan variables de instancia para exactamente esto).

El ejemplo que he utilizado contiene dos invocaciones públicas distintas. Para ver un caso en el que las variables de instancia todavía se utilizan a pesar de que solo se realizó una llamada, consulte la implementación de ActiveRecord #update_attributes. El cuerpo del método es simplemente load(attributes, false) && save.¿Por qué #save no pasa ningún argumento (como el nuevo name) aunque va a estar en el cuerpo de guardar donde algo como UPDATE users SET name='foobar' WHERE id=1;? Es porque cosas como el nombre es información que pertenece a la instancia.

Por el contrario, podemos ver un caso en el que las variables de instancia no tienen sentido de usar. Mire la implementación de #link_to_if, un método que acepta un argumento boolean-ish (generalmente una expresión en el código fuente) junto con argumentos que son comúnmente aceptados por #link_to, como la URL a la que se debe vincular. Cuando la condición booleana es verdadera, necesita pasar el resto de los argumentos al #link_to e invocarlo. No tendría mucho sentido asignar aquí variables de instancia porque no diría que el contexto de invocación aquí (el representador) contiene esa información en la instancia. El renderizador en sí no tiene una "URL para vincular", y en consecuencia, no debe ser enterrado en una variable de instancia.

+1

Gracias por esta gran explicación con ejemplos, especialmente sobre si es una buena práctica o no. – tackleberry

16

Esas son las variables de instancia de clase y son una cosas perfectamente legítimas en rubí: clases también son objetos (instancias de la clase) y así tener variables de instancia.

Una cosa a tener en cuenta es que cada subclase tendrá su propio conjunto de variables de instancia de clase (después de todo, estos son diferentes objetos): Si una subclase DummyClass, métodos de clase en la subclase no serían capaces de ver @arr.

Las variables de clase (@@foo) son, por supuesto, al revés: toda la jerarquía de clases comparte las mismas variables de clase.

+0

hmm eso es algo diferente. Así que no hay nada de qué preocuparse, siempre y cuando no herede una nueva clase. esas son buenas noticias, gracias! – tackleberry

Cuestiones relacionadas