Как возможно, что у меня могут быть переменные экземпляра в модуле, хотя я не могу создать экземпляр модуля? Какова была бы цель @stack в модуле Stacklike ниже?
module Stacklike
def stack
@stack ||= []
end
end
Как возможно, что у меня могут быть переменные экземпляра в модуле, хотя я не могу создать экземпляр модуля? Какова была бы цель @stack в модуле Stacklike ниже?
module Stacklike
def stack
@stack ||= []
end
end
Подумайте о переменной экземпляра как о том, что будет существовать в любом классе, который включает ваш модуль, и все будет иметь смысл:
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"
См. ниже:
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 of class A.
Почему такой дизайн?
Это дизайн или иногда исходит из требований. Скажите, что вас попросили написать код операции стека, который будет использоваться двумя компаниями, осуществляющими бронирование билетов, Say a и B. Теперь a - политика стека для своих клиентов, чтобы обслуживать, но также они имеют больше формальности с этим. B компания также использует политику стека со своими формальностями, которая отличается от a. Таким образом, в случае проектирования Stack внутри class A и class B лучше написать его в общем месте, так как обе a и B имеют общую функциональность внутри них. В будущем, если к вам придет другая компания C, вы также можете использовать этот модуль в своем классе, не переписывая одну и ту же функциональность для каждого a, B и C. Могут быть больше мыслей, но надеюсь, что это поможет вам ответить на вопрос о своей последней части вопросов.
Что все о концепции. Надеюсь, что это поможет.
Ура!!
Когда вы включаете модуль в класс, все его методы экземпляра эффективно "вставлены" в класс хоста. Поэтому, если у вас есть:
class Lifo
include Stacklike
end
l = Lifo.new
l.add_to_stack(:widget)
Затем l теперь имеет переменную экземпляра @stack, введенную из Stacklike.
Когда вы включаете модуль Stacklike в какой-то другой класс, эта переменная экземпляра будет доступна, как если бы она была определена в этом классе. Это дает вам возможность устанавливать и обрабатывать переменные экземпляра базового класса из самого модуля.