Когда использовать модуль, а когда использовать класс - PullRequest
20 голосов
/ 20 апреля 2010

Я сейчас работаю с книгой Грегори Брауна Ruby Best Practices . Вначале он говорил о рефакторинге некоторой функциональности от вспомогательных методов в связанном классе к некоторым методам в модуле, затем имел модуль extend self.

Не видел, чтобы раньше, после быстрого поиска в Google, обнаружил, что extend self в модуле позволяет методам, определенным в модуле, видеть друг друга, что имеет смысл.

Теперь мой вопрос: когда бы вы сделали что-то подобное

module StyleParser
  extend self

  def process(text)
    ...
  end

  def style_tag?(text)
    ...
  end
end

и затем обратитесь к нему в тестах с

@parser = Prawn::Document::Text::StyleParser

в отличие от чего-то подобного?

class StyleParser

  def self.process(text)
    ...
  end

  def self.style_tag?(text)
    ...
  end
end 

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

Ответы [ 3 ]

39 голосов
/ 20 апреля 2010

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

Имея это в виду, я думаю, что различие заключается в том, действительно ли вам нужен класс. Метод класса кажется более подходящим, когда у вас есть существующий класс, который нуждается в некоторой одноэлементной функциональности. Если то, что вы делаете, состоит только из одноэлементных методов, имеет смысл реализовать его как модуль и напрямую обращаться к нему через модуль.

8 голосов
/ 20 апреля 2010

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

Класс - это фабрика для объектов (обратите внимание на множественное число). Если вы не хотите создавать несколько экземпляров класса, нет необходимости в его существовании.

Модуль - это контейнер для методов, который используется несколькими объектами. Если вы не смешиваете модуль с несколькими объектами, нет необходимости в его существовании.

В этом случае, похоже, вы просто хотите объект. Так что используйте один:

def (StyleParser = Object.new).process(text)
  ...
end

def StyleParser.style_tag?(text)
  ...
end

Или альтернативно:

class << (StyleParser = Object.new)
  def process(text)
    ...
  end

  def style_tag?(text)
    ...
  end
end

Но, как уже писал @Azeem: для правильного решения вам нужно больше контекста. Я недостаточно знаком с внутренностями Prawn, чтобы понять, почему Грегори принял именно это решение.

0 голосов
/ 20 апреля 2010

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

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