2010-02-19 9 views
13

W jaki sposób uzyskujesz dostęp do zmiennej instancji w metodzie mixin? Mogę wymyślić 2 sposoby, ale oba wydają się problematyczne.Jak uzyskać dostęp do zmiennej instancji w metodzie mixin?

  1. Mieć metodę mixin dostęp do zmiennej instancji bezpośrednio jak każda metoda klasy, np. Self.text. Problem polega na tym, że nakłada ograniczenia na to, gdzie można zastosować metodę mixin, i zmusza klasę do miksowania, aby konkretna metoda instancji została nazwana w określony sposób.

  2. do zmiennej przykład jako parametr Metoda taka, która będzie prowadzić do kodu:

przykład

self.do_something(self.text) 

lub

@thing.do_something(@thing.text) 

który wygląda nieprzyjemny dla mnie i nie jest zgodny z zasadami orientacji obiektowej.

Czy jest jakaś inna metoda, aby to zrobić?

Odpowiedz

21

Ogólnie , unikaj posiadania zmiennych składowych dostępu do mixin: To bardzo ciasna forma sprzężenia, która może niepotrzebnie utrudnić przyszły refaktoryzację.

Jedną z przydatnych strategii jest to, że Mixin zawsze uzyskuje dostęp do zmiennych za pomocą akcesorów. Tak więc, zamiast:

#!/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" 

wstawka dostęp do „tekst” akcesor, który jest zdefiniowany przez klasę w tym:

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" 

Co jeśli trzeba zawierać wstawek w tej klasie?

class Foo 

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

end 

Używanie ogólnych i powszechnych nazw danych w mixins może prowadzić do konfliktów, gdy klasa include używa tej samej nazwy.W takim przypadku mają wygląd wstawionej do danych z mniej nazwa zwyczajowa:

module Mixin 

    def do_something 
    p mixin_text 
    end 

end 

i niech w tym klasa określić odpowiedni akcesor:

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" 

w ten sposób accessor działa jako swego rodzaju "impedance matcher" lub "translator" między danymi miksu i danymi klasy włączającej.

+0

Dzięki Wayne, naprawdę to wyjaśniłeś. – dangerousdave

1

Możesz podać tym przypadku metodę się w tym module, ale trzeba uważać, aby nie nadpisać istniejące metody

Przykład (w module jesteś mieszania w):

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

Dzięki Kylo, ​​ale wydaje się to nadal ograniczać sposób użycia mixina. Klasa pobierająca ją musi nadal mieć zmienną instancji @text. – dangerousdave

2

Instancji nazwy zmiennych zacznij w ruby ​​z @ eg. @variable. Można acces je o tej nazwie z modułu dołączyć

module M 
    def t 
    @t 
    end 
end 

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

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

Jeśli wan't dostęp @t gdy nie jest zdefiniowana w klasie, zanim będzie można zrobić to w ten sposób

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