2015-02-17 2 views
1

Я застрял здесь, потому что я беспокоюсь о том, лучше ли использовать метод класса дочернего класса из родительского класса?Вызов метода подкласса из суперкласса - шаблон проектирования

module Zoo 

    class Animals 
    class << self 
     def update 
     if self.whatever == ... # Calls method 'whatever' from Tiger class 
      # do sth. 
     end  
     end 
    end 
    end 

    class Tiger < Animals  
    def update 
     super 
    end 
    class << self 
     def whatever 
     "whatever from tiger class" 
     end 
    end 
    end 
end 

Zoo::Tiger.update 

Это работает, но я был бы признателен за лучшее решение этой проблемы. Я хочу как можно больше следовать лучшим решениям в отличие от некоторых пользовательских хаков.

Заранее благодарен!

+1

Ваш метод 'update' в' Tiger' никогда не вызывается. Класс singleton класса Tiger наследует метод, определенный в одиночном классе «Животные». – Max

ответ

1

Попробуйте это:

class Animals 
    def self.update 
    puts "self = #{self} in Animals::update" 
    if whatever == "Happy Days" 
     puts "The Fonz rules" 
    end  
    end 
end 

class Tiger < Animals  
    def self.whatever 
    "Happy Days" 
    end 
end 

Tiger.update 
    # self = Tiger in Animals::update 
    # The Fonz rules 

Прежде чем обсуждать это, несколько заметок:

  • Я удалил модуль Zoo и метод экземпляра Tiger#update, поскольку они не имеют отношения к этому вопросу.
  • Я удалил self. из self.whatever, поскольку он не нужен (self предполагается, если явного приемника нет).
  • Я определил методы класса более традиционным способом (но нет ничего плохого в том, как определяет их ОП).
  • update должен вызываться только из подклассов, так как Animal.update поднимет «исключение метода или локальной переменной« независимо ».

Важным моментом здесь является то, что Tiger.update вызывает метод Animal::update, так же, как если бы update был определен в Tiger, а не будучи унаследована от Animal. Вот почему:

Tiger.methods.include?(:update) #=> true 

Поэтому «вызов метода класса дочернего класса из родительского класса» неверен; Tiger::whatever вызывается из дочернего класса. Ничего не вызывается из родительского класса, потому что self никогда не равен Animals, когда вызывается Tiger::update. Это не просто семантика.

3

Это очень обычный образец. Затем вы можете реализовать whatever по-разному в каждом дочернем классе без необходимости переопределять update в каждом из них. Все, что я хотел бы добавить:

def self.whatever 
    raise NotImplementedError, 'Class must implement whatever' # or some useful message 
end 

к Animal класса. Таким образом, если вы вызываете ChildClass.update из дочернего класса, который не реализует whatever, вы получаете полезную ошибку.

+0

Отлично. Спасибо, @ptd! – user1557892

+0

В дополнение к добавлению метода класса исключения, 'whatever' to' Animals', может быть полезно сделать первую строку 'Animals :: update' следующей:' raise NotImplementedError ', обновление нужно только вызывать из подклассы ", если самостоятельно == Животные. Возможно, ваше сообщение об ошибке '' class # {self} должно реализовать ... "'. –

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