2013-03-18 16 views
25

Wie ist es möglich, dass ich Instanzvariablen in einem Modul haben kann, obwohl ich keine Instanz des Moduls erstellen kann? Was wäre der Zweck von @stack in Modul Stacklike unten?Instanzvariablen in Modulen?

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

Wenn Sie Instanzvariablen verwenden/initialisieren möchten, berücksichtigen Sie die Vererbung anstelle von mixin. –

Antwort

37

Denken Sie an die Instanzvariable als etwas, das in jeder Klasse existieren, die das Modul enthält, und die Dinge ein wenig mehr Sinn machen:

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 

gibt „1“

+5

Ist das wirklich ein gutes Design? Ich meine, wenn Sie ein Modul hinzufügen, ohne zu wissen, was darin enthalten ist, können Sie Probleme bekommen, wo Variablen außer Kraft gesetzt werden und alle Arten von Problemen auftreten. Speziell in dem Fall, in dem das Modul eine Variable benötigt, um den Zustand zu speichern. Gibt es vielleicht eine Möglichkeit, einen Zustand in einem Modul zu haben, ohne es freizulegen? – Automatico

+4

Nein, es ist kein gutes Design. Aber bei Modulen und/oder Monkeypatching sind alle Wetten sowieso aus. Schließlich kann sich das Verhalten eines Ruby-Programms in der Reihenfolge ändern, in der Edelsteine ​​benötigt werden, ganz zu schweigen von den einzelnen Modulen in einem Edelstein/einer Anwendung. – mcfinnigan

3

Wenn Wenn Sie ein Modul in eine Klasse aufnehmen, werden alle seine Instanzmethoden effektiv in die Host-Klasse "eingefügt". Also, wenn Sie haben:

class Lifo 
    include Stacklike 
end 

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

Dann l hat nun eine Instanzvariable @stack, brachte aus Stacklike.

+0

Was ist mit Kollisionen? Wenn ich in Lifo eine @ Stack-Variable habe, was wird bevorzugt? –

+0

Sie kollidieren. '@ stack' bezieht sich sowohl auf den nativen' Lifo' als auch auf den 'Stacklike'. Pickaxe schlägt vor, deinem Mix keinen Status zu geben; Stattdessen muss man festlegen, dass alles, was es beinhaltet, eine "Stack" -Methode bereitstellen muss. In vielerlei Hinsicht ist eine Mischung mit dem Zustand kein Mixin. Es ist eine Klasse. – Chowlett

1

Wenn Sie das Modul Stacklike in eine andere Klasse aufnehmen, ist diese Instanzvariable verfügbar, als wäre sie in dieser Klasse definiert. Damit haben Sie die Möglichkeit, Instanzvariablen der Basisklasse aus dem Modul selbst zu setzen und zu bearbeiten.

11

Siehe unten:

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 

Ausgang:

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

Erläuterung: Ja, Module Instanzvariablen in den class vorhanden sind, wenn man sich in der Klasse include würde. Aber Sie können sehen, dass zeigt false als @stack ist immer noch nicht definiert bis A. Unter Punkt B habe ich die Instanzvariable @stack definiert. So lautet die Aussage in Punkt C, Ausgaben wie true. Die Modulinstanzvariablen werden nicht vom Modul selbst erzeugt, sondern können von den class Instanzen ausgeführt werden, wenn das class dieses Modul enthält. Statement in E Ausgängen [] als noch die Instanzvariablen dieser Punkt wurde nicht definiert, aber wenn Sie die Ausgabe für die Linie D siehe ist es bewiesen, die @stack innerhalb des Objekts a von class A ist.

Warum solch ein Design?

Dies ist das Design oder manchmal kommen von den Anforderungen. Angenommen, Sie wurden aufgefordert, einen Stapeloperationscode zu schreiben, der von zwei Ticketbuchungsfirmen verwendet wird, Sagen Sie A und B. Jetzt A sind Stack-Politik für ihre Kunden zu bedienen, aber sie haben mehr Formalitäten damit. B Firma verwendet auch Stack-Politik mit ihren eigenen Formalitäten, die sich von A unterscheidet. So im Falle des Entwerfens Operation innerhalb class A und class B, bessere Idee, es in einen allgemeinen Platz zu schreiben, wie sowohl A als auch B diese Funktionalität haben, die in ihnen üblich ist.Wenn in Zukunft eine andere Firma C zu Ihnen kommt, können Sie dieses Modul auch in ihrer Klasse verwenden, ohne die gleiche Funktionalität für jede A, B und C neu zu schreiben. Es kann mehr Gedanken geben, aber hoffen, dass dies dir hilft, dir selbst für deinen letzten Teil der Fragen zu antworten.

Das ist alles über das Konzept. Ich hoffe es hilft.

Prost !!

+0

Nicht ganz überraschend. Probiere 'a = A.new; a.add_to_stack (1); a.instance_variables' – Chowlett

+0

@Chowlett warten lass mich geben, ich habe Netzwerkproblem. –

+0

@Chowlett Gibt es noch Verwirrung in dir? Bitte lass es mich wissen. –