Что является более эффективным: response_to? или метод, который ничего не делает? - PullRequest
0 голосов
/ 15 марта 2020

Это то, о чем я задумывался годами: эффективнее ли проверять, есть ли у объекта метод, а затем, если он есть, вызывать метод, ИЛИ всегда иметь метод, который ничего не делает, всегда вызывать этот метод? и подклассы должны переопределять этот метод по мере необходимости.

Рассмотрим этот пример:

class Base
    def mymethod
        respond_to?(:hook) and hook()
        puts 'stuff in mymethod'
    end
end

class SubClass < Base
    def hook
        puts 'stuff in hook'
    end
end

Итак, в этой ситуации мы в основном добавили обработчик событий. Если у подкласса есть метод с именем hook, то этот метод вызывается в mymethod. Это довольно распространенная методика проектирования. Но, конечно, для этого требуется проверить, существует ли метод.

Еще один метод для реализации того же результата заключается в разработке Base следующим образом:

class Base
    def mymethod
        hook()
        puts 'stuff in mymethod'
    end

    def hook
    end
end

Теперь вы не можете приходится каждый раз проверять, есть ли метод с именем hook, но вам нужно каждый раз вызывать этот метод, даже если он ничего не делает.

Так что же более эффективно? Что легче понять программисту? Разница настолько мала, что это просто вопрос личных предпочтений?

Ответы [ 3 ]

4 голосов
/ 15 марта 2020

Краткий ответ: Это настолько тривиально, что вам все равно.

Длинный ответ:


require 'benchmark'

class Base
  def mymethod
    respond_to?(:hook) and hook()
  end
end

class SubClass < Base
  def hook
  end
end

class Parent
  def mymethod
    hook
  end

  def hook
  end
end

class Child < Parent
end

s = SubClass.new
c = Child.new
n = 10000000
Benchmark.bm(7) do |x|
  x.report(:respond_to?) { n.times {s.mymethod} }
  x.report(:empty) { n.times {c.mymethod} }
end

Результат:

                   user     system      total        real
respond_to?    1.263308   0.011612   1.274920 (  1.327659)
empty          0.789442   0.010208   0.799650 (  0.900536)

Итак, используя respond_to? немного медленнее, чем при использовании пустого метода.

0 голосов
/ 15 марта 2020

respond_to? всегда будет медленнее. Это вызовет как минимум один (в отрицательном случае) и, возможно, два (в положительном случае) вызова метода. Пустой базовый случай метода, с другой стороны, это всего лишь один вызов метода.

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

0 голосов
/ 15 марта 2020

Offtopi c немного, но я бы сказал, что использование respond_to? с неявным приемником в том смысле, в котором вы предлагаете, является запахом кода - это означает, что вы делаете странные вещи, которые нарушают подтип ( LSP) ).

Иногда это может быть действительно необходимо для некоторых черных магов метапрограммирования c, отладки, исправления живого приложения и т. Д. c - но я уверен, что в таких случаях вы не будете задавать такие вопросы, как это (вы точно будете знать, почему вы это делаете, конечная эффективность наверняка станет меньшей проблемой).

Так что, для меня, вопрос не в эффективности. Всегда «уважайте» (следуйте) LSP, если можете, и играйте с respond_to? только в случае необходимости (и в этом случае производительность может быть не основным критерием)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...