Как правильно инкапсулировать фабричные методы из производных классов при реализации фабрики в базовом классе? - PullRequest
1 голос
/ 27 марта 2019

Я пытаюсь создать простой класс с возможностью регистрации производных классов для создания из базового класса.Однако я не могу найти хороший способ инкапсулировать эту функциональность от потомков.

Переменные класса выглядят для меня плохой идеей, потому что они доступны везде в цепочке наследования.Поэтому я пытаюсь сделать что-то с переменными экземпляра класса.Прекрасно будет, что все методы класса будут недоступны, кроме register_as

class A
  @registered = {}
  class << self
    def register_as(name)
      A.registered[name] = self
    end

    def known
      A.registered
    end

    protected
    attr_accessor :registered
  end

  def helpful_method
  end

end

class B < A
  class << self
    def reg_trash
      A.registered[:trash] = :trash
    end
  end
  B.register_as :b
end

B.reg_trash
p A.known

Однако зарегистрированный по-прежнему доступен из класса B.В настоящее время похоже, что единственный возможный вариант - разделить класс A на выделенный класс Factory, а класс A будет содержать только полезные методы экземпляра.Может быть, что-то можно сделать с помощью .inherited и .undef_method, не так ли?

1 Ответ

2 голосов
/ 27 марта 2019

Может быть, можно что-то сделать с помощью .inherited и .undef_method, не так ли?

Да, это возможно.Но идея пахнет, как для меня - вы нарушите заменяемость.

Если вы не хотите, чтобы «производные» классы наследовали поведение родителя, почему вы вообще используете наследование?Вместо этого попробуйте композицию и смешайте только то поведение, которое вам нужно.Например, что-то вроде этого может сработать ( очень грязный пример, но я надеюсь, что вы поняли):

class A
  module Registry
    def register_as(name)
      A.register_as(name, self)
    end
  end

  @registered = {}

  def self.register_as(name, klass)
    @registered[name] = klass
  end

  def self.known
    @registered
  end
end

class B
  extend A::Registry
  register_as :b  
end

class C
  extend A::Registry
  register_as :c
end

A.known # => {:b => B, :c => C}
...