Сэнди Метц рассказывает об одном решении этой проблемы и о том, как действительно решить ее, в своей книге «Практический объектно-ориентированный дизайн в Ruby (POODR)».
То, что она предлагает (и я склонен согласиться с тем, что пока это работает лучше всего для меня), это ввести подкласс FooSub
в мастер-класс Foo
.
Это будет сделано в foo.rb с:
1 class Foo
2 def initialize(foo_sub:)
3 end
4 end
для поддержания чистоты кода и его легкого изменения вы должны затем обернуть foo_sub
в метод-обертку, чтобы ваш класс теперь выглядел следующим образом:
1 class Foo
2
3 attr_reader :foo_sub
4
5 def initialize(foo_sub:)
6 @foo_sub = foo_sub
7 end
8 end
(здесь attr_reader
устанавливает метод с именем foo_sub
, и тогда все, что передается в значение инициализированного хэша, является экземпляром foo_sub, поэтому @foo_sub
(строка 6) можно установить в Значение метода foo_sub
).
Теперь у вас есть класс FooSub
без требований, что делает его независимым от чего-либо:
1 class FooSub
2 SOME_CONSTANT = 1
3 end
и вы можете добавить метод к вашему Foo
классу, который имеет доступ к #SOME_CONSTANT:
1 class Foo
2
3 attr_reader :foo_sub
4
5 def initialize(foo_sub:)
6 @foo_sub = foo_sub
7 end
8
9 def foo
10 foo_sub.SOME_CONSTANT
11 end
12 end
На самом деле вы настраиваете метод, который возвращает экземпляр foo_sub @foo_sub
(который вводится при инициализации), с добавленным к нему методом #SOME_CONSTANT. Ваш класс просто ожидает, что все, что введено при инициализации, ответит на #SOME_CONSTANT. Поэтому, чтобы это работало, вам нужно ввести класс FooSub
при настройке Foo
в REPL (например, IRB или PRY):
PRY
[1]> require 'foo'
[2]> => true
[3]> require 'foo_sub'
[4]> => true
[5]> foo_sub = FooSub.new
[6]> => #<FooSub:0x007feb91157140>
[7]> foo = Foo.new(foo_sub: foo_sub)
[8]> => #<Foo:0x007feb91157735 @foo_sub=FooSub:0x007feb91157140>
[9]> foo.foo
[10]> => 1
однако, если вы введете что-то еще, вы получите:
PRY
[1]> require 'foo'
[2]> => true
[3]> require 'foo_sub'
[4]> => true
[5]> foo_sub = FooSub.new
[6]> => #<FooSub:0x007feb91157140>
[7]> foo = Foo.new(foo_sub: 'something else as a string')
[8]> => #<Foo:0x007feb91157735 @foo_sub='something else as a string'>
[9]> foo.foo
[10]> => UNDEFINED CONSTANT #SOME_CONSTANT ERROR MESSAGE
Я не знаю, что именно сообщение об ошибке будет читать в строке 10, но думаю в том же духе. Эта ошибка произошла из-за того, что вы фактически пытались запустить метод #SOME_CONSTANT для строки «что-то другое как строка» или 'something else as a string'.SOME_CONSTANT
, которая, очевидно, не будет работать.