2010-02-19 13 views
13

¿Cómo se accede a una variable de instancia dentro de un método de mixin? Puedo pensar en 2 formas, pero ambas parecen problemáticas.¿Cómo se accede a una variable de instancia dentro de un método de mixin?

  1. Hacer que el mixin acceso método de la variable de instancia directamente como cualquier método de clase sería, por ejemplo self.text. El problema con esto es que impone restricciones sobre dónde se puede utilizar el método de mixin y obliga a la clase que realiza la mezcla a tener un método de instancia particular nombrado de una manera particular.

  2. pasar la variable instancia como un parámetro para el método mixin, lo que resultaría en código como este:

ejemplo

self.do_something(self.text) 

o

@thing.do_something(@thing.text) 

que parece desagradable para mí, y no se ajusta a los principios de orientación del objeto.

¿Hay alguna otra manera de hacerlo ?, ¿tengo razón en preocuparme?

Respuesta

21

En general , evite que mixins acceda a las variables miembro: es una forma muy estrecha de acoplamiento que puede hacer que la futura refactorización sea innecesariamente difícil.

Una estrategia útil es que el Mixin siempre acceda a las variables a través de los descriptores de acceso. Así, en lugar de:

#!/usr/bin/ruby1.8 

module Mixin 

    def do_something 
    p @text 
    end 

end 

class Foo 

    include Mixin 

    def initialize 
    @text = 'foo' 
    end 

end 

Foo.new.do_something  # => "foo" 

el mixin accede al descriptor de acceso "Texto", que se define por la clase incluyendo:

module Mixin 

    def do_something 
    p text 
    end 

end 

class Foo 

    attr_accessor :text 

    include Mixin 

    def initialize 
    @text = 'foo' 
    end 

end 

Foo.new.do_something  # => "foo" 

¿Qué pasa si es necesario incluir el Mixin en esta clase?

class Foo 

def initialize 
    @text = "Text that has nothing to do with the mixin" 
end 

end 

El uso de nombres de datos genéricos y comunes en mixins puede conducir a conflictos cuando la clase incluyendo utiliza el mismo nombre.En ese caso, tener la mirada mixin para los datos con un nombre menos común:

module Mixin 

    def do_something 
    p mixin_text 
    end 

end 

y dejar que la clase que incluye definir el descriptor de acceso apropiado:

class Foo 

    include Mixin 

    def initialize 
    @text = 'text that has nothing to do with the mixin' 
    @something = 'text for the mixin' 
    end 

    def mixin_text 
    @something 
    end 

end 

Foo.new.do_something  # => "text for the mixin" 

De esta manera, el descriptor de acceso actúa como una especie de "impedance matcher" o "translator" entre los datos de la mezcla y los datos de la clase incluida.

+0

Gracias Wayne, realmente has aclarado esto. – dangerousdave

1

Puede proporcionar este método de instancia a sí mismo en este módulo, pero hay que tener cuidado de no sobrescribir método existente

Ejemplo (en el módulo que se está mezclando en):

def text 
    @text ||= "" 
end 
+1

Gracias Kylo, ​​pero esto todavía parece restringir cómo se puede utilizar mixin. La clase que lo tira debe seguir teniendo una variable de instancia @text. – dangerousdave

2

nombres de las variables de instancia comenzar en ruby ​​con un @ ej. @variable. Puede acces con este nombre de un módulo de incluir

module M 
    def t 
    @t 
    end 
end 

class A 
    include M 
    def initialize(t) 
    @t= t 
    end 
end 

A.new(23).t # => 23 

Si quieres probar a acceder @t cuando no está definido en la clase antes de que pueda hacerlo de esta manera

module M 
    def t 
    instance_variable_defined?("@t") ? @t : nil 
    end 
end 
Cuestiones relacionadas