2013-03-18 22 views
25

Jak to możliwe, że mogę mieć zmienne instancji w module, mimo że nie mogę utworzyć instancji modułu? Jaki byłby cel poniższego modułu @stack w module Stacklike?Zmienne instancji w modułach?

module Stacklike 
    def stack 
    @stack ||= [] 
    end 
end 
+0

Jeśli chcesz użyć/zainicjować zmienne instancji, rozważ dziedziczenie zamiast mixin. –

Odpowiedz

37

Pomyśl o zmiennej instancji jako coś, co będzie istnieć w każdej klasie, która zawiera moduł, a rzeczy zrobić trochę więcej sensu:

module Stacklike 
    def stack 
    @stack ||= [] 
    end 

    def add_to_stack(obj) 
    stack.push(obj) 
    end 

    def take_from_stack 
    stack.pop 
    end 
end 

class ClownStack 
    include Stacklike 

    def size 
    @stack.length 
    end 
end 

cs = ClownStack.new 
cs.add_to_stack(1) 
puts cs.size 

wyjście wola „1”

+5

Czy to naprawdę dobry projekt? Chodzi mi o to, że jeśli umieścisz moduł bez wiedzy o tym, co się w nim znajduje, możesz napotkać problemy, gdy zmienne ulegają przesłonięciu i pojawiają się wszelkiego rodzaju problemy. Zwłaszcza w przypadku, gdy moduł potrzebuje pewnej zmiennej do zapisania stanu. Czy istnieje sposób na posiadanie stanu w module bez ujawniania go? – Automatico

+4

Nie, to nie jest dobry projekt. Ale wszystkie zakłady są wyłączone w każdym razie, jeśli chodzi o moduły i/lub monkeypatching. W końcu zachowanie programu ruby ​​może zmienić się w kolejności, w jakiej są wymagane klejnoty, nie mówiąc już o tym, co robią poszczególne moduły w klejnocie/aplikacji. – mcfinnigan

3

Kiedy zawierasz moduł w klasie, wszystkie jego metody instancji są skutecznie "wklejane" do klasy hosta. Więc jeśli masz:

class Lifo 
    include Stacklike 
end 

l = Lifo.new 
l.add_to_stack(:widget) 

Następnie l ma teraz instancję zmiennej @stack, sprowadzone z Stacklike.

+0

A co z kolizjami? Jeśli w Lifo mam zmienną @stack, co ma pierwszeństwo? –

+0

Oni zderzają się. '@ stack' odnosi się zarówno do tego natywnie w' Lifo' i do tego z 'Stacklike'. Kilof sugeruje, że nie podajesz swojego mixina w żadnym stanie; zamiast tego, powiedz, że wszystko, co obejmuje, musi zapewniać metodę "stosu". Pod wieloma względami mixin ze stanem to nie mixin. To jest klasa. – Chowlett

1

Po dodaniu modułu Stacklike do innej klasy ta zmienna instancji będzie dostępna tak, jakby była zdefiniowana w tej klasie. Daje to możliwość ustawienia i obsługi zmiennych instancji klasy bazowej z samego modułu.

11

Patrz poniżej:

p RUBY_VERSION 
module Stacklike 
    def stack 
    @stack ||= [] 
    end 

    def add_to_stack(obj) 
    stack.push(obj) 
    end 

    def take_from_stack 
    stack.pop 
    end 
end 

class A 
include Stacklike 
end 

a = A.new 
p a.instance_variables #<~~ E 
p a.instance_variable_defined?(:@stack) #<~~ A 
a.add_to_stack(10) #<~~ B 
p a.instance_variable_defined?(:@stack) #<~~ C 
p a.instance_variables #<~~ D 

wyjściowa:

"1.9.3" 
[] 
false 
true 
[:@stack] 

Objaśnienie: Tak, Module instancji zmienne są obecne w class kiedy byś include je wewnątrz klasy. Ale widać, że p a.instance_variable_defined?(:@stack) pokazuje false jako @stack nadal nie jest zdefiniowany do A. W punkcie B Zdefiniowałem zmienną instancji @stack. Tak więc oświadczenie w punkcie C, wyprowadza jako true. Zmienne instancji modułu nie są tworzone przez sam moduł, ale można to zrobić za pomocą instancji class, jeśli moduł ten zawierał class. Oświadczenie w E wyjścia [] jako że jeszcze punkt zmienna instancji nie została określona, ​​ale jeśli widzisz wyjście dla linii D, to okazał się @stack jest wewnątrz obiektu a z class A.

Dlaczego taki projekt?

To jest projekt, a czasem wynika z wymagań. Załóżmy, że zostałeś poproszony o napisanie kodu operacji stosu, który będzie używany przez dwie firmy zajmujące się rezerwowaniem biletów, Powiedz A i B. Teraz A to zasady dotyczące kupowania dla klientów, którzy mają służyć, ale także mają dodatkowe formalności. B Firma również stosuje politykę stosu z własnymi formalnościami, która różni się od A. Tak więc w przypadku projektowania wewnątrz class A i class B, lepszym pomysłem jest napisanie go we wspólnym miejscu, ponieważ Zarówno A, jak i B mają wspólną wspólną dla nich funkcjonalność.W przyszłości, jeśli pojawi się inna firma C, możesz również użyć tego modułu w swojej klasie, bez przepisywania tej samej funkcjonalności dla każdego z następujących A, B i C. Może być więcej myśli, ale mam nadzieję, że to pomoże ci odpowiedzieć sobie na ostatnią część pytań.

To wszystko na temat koncepcji. Mam nadzieję, że to pomoże.

Pozdrawiam!

+0

Nie do końca zaskakujące. Spróbuj 'a = A.new; a.add_to_stack (1); a.instance_variables' – Chowlett

+0

@Chowlett czekać Pozwól mi dać, mam problem z siecią. –

+0

@Chowlett Czy jest jeszcze jakieś zamieszanie? proszę dać mi znać wtedy. –

Powiązane problemy