2013-03-18 3 views
25

Как возможно, что у меня могут быть переменные экземпляра в модуле, хотя я не могу создать экземпляр модуля? Какова была цель @stack в модуле Stacklike ниже?Переменные экземпляра в модулях?

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

Если вы хотите использовать/инициализировать переменные экземпляра, рассмотрите наследование вместо mixin. –

ответ

37

Think переменной экземпляра, как нечто такое, что будет существовать в любом классе, который включает в свой модуль, и вещи сделать немного больше смысла:

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 

Выход «1»

+5

Действительно ли это хороший дизайн? Я имею в виду, если вы включите модуль, не зная, что в нем, вы можете столкнуться с проблемами, когда переменные становятся переопределенными и возникают всевозможные проблемы. Специально в случае, когда модулю требуется какая-либо переменная для хранения состояния в. Может ли быть способ иметь состояние в модуле, не подвергая его воздействию? – Automatico

+4

Нет, это не хороший дизайн. Но все ставки отключаются, когда дело доходит до модулей и/или обезьян. В конце концов, поведение рубиновой программы может измениться по порядку, в котором требуются драгоценные камни, не говоря уже о том, что делают отдельные модули в камне/приложении. – mcfinnigan

3

Когда вы включаете модуль в класс, все его методы экземпляра эффективно «вставлены» в класс хоста. Так что если у вас есть:

class Lifo 
    include Stacklike 
end 

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

Тогда l теперь имеет экземпляр переменной @stack, привезенный из Stacklike.

+0

Как насчет конфликтов? Если в Lifo у меня есть переменная @stack, что предпочитает? –

+0

Они сталкиваются. '@ stack' относится как к одному изначально в' Lifo', так и к 'Stacklike'. Пикакс предлагает не давать вашему микшину какое-либо состояние; вместо этого укажите, что все, что включает в себя, должно содержать метод 'stack'. Во многих отношениях смесь с состоянием не является миксином. Это класс. – Chowlett

1

Когда вы включаете модуль Stacklike в какой-то другой класс, эта переменная экземпляра будет доступна, как если бы она была определена в этом классе. Это дает вам возможность устанавливать и обрабатывать переменные экземпляра базового класса из самого модуля.

11

Смотрите ниже:

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 

Выход:

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

Пояснение: Да, Module переменные экземпляра присутствуют в class когда вы include их внутри класса. Но вы можете видеть, что p a.instance_variable_defined?(:@stack) показывает false как @stack еще не определен до A. В точке B Я определил переменную экземпляра @stack. Таким образом, утверждение в пункте C, выходы как true. Средние переменные экземпляра модуля не создаются самим модулем, но это может быть сделано экземплярами class, если в этот модуль включен class. Заявление в E выходы [], как до сих пор эта точка переменная экземпляра не была определена, но если вы видите выход для линии D , она доказана @stack внутри объекта a из class A.

Почему такой дизайн?

Это дизайн или иногда исходит из требований. Скажите, что вас попросили написать код операции стека, который будет использоваться двумя компаниями по бронированию билетов, скажем A и B. Теперь A - политика стека для своих клиентов, чтобы обслуживать, но также они имеют больше формальности с этим. B компания также использует политику стека со своими формальностями, которая отличается от A. Таким образом, в случае проектирования Stack операции внутри class A и class B, лучше написать его в обычном месте, так как оба A и B имеют общую функциональность в них.В будущем, если к вам придет другая компания C, вы также можете использовать этот модуль в своем классе, не переписывая одну и ту же функциональность для каждого A, B и C. Могут быть больше мыслей, но надеюсь, что это поможет вам ответить на вопрос о своей последней части вопросов.

Это все о концепции. Надеюсь, поможет.

Cheers !!

+0

Не совсем удивительно. Попробуйте 'a = A.new; a.add_to_stack (1); a.instance_variables' – Chowlett

+0

@Chowlett wait Позвольте мне дать его, у меня проблема с сетью. –

+0

@Chowlett Есть ли какое-то замешательство в вас? тогда дайте мне знать. –

Смежные вопросы