Как возможно, что у меня могут быть переменные экземпляра в модуле, хотя я не могу создать экземпляр модуля? Какова была бы цель @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 в какой-то другой класс, эта переменная экземпляра будет доступна, как если бы она была определена в этом классе. Это дает вам возможность устанавливать и обрабатывать переменные экземпляра базового класса из самого модуля.