Использование Class vs Module для упаковки кода в Ruby - PullRequest
2 голосов
/ 14 декабря 2011

Допустим, у меня есть несколько связанных функций, которые не имеют постоянного состояния, скажем, различные операции в пакете различий строк.Я могу определить их в классе или модуле (используя self), и к ним можно получить доступ точно так же:

class Diff
  def self.diff ...
  def self.patch ...
end

или

module Diff
  def self.diff ...
  def self.patch ...
end

Затем я могу сделать Diff.patch(...).Что «лучше» (или «правильно»)?

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

Редактировать: пример изменен сматрица для сравненияМатрица - ужасный пример, поскольку имеет состояние, и все начали объяснять, почему лучше писать их как методы, а не отвечать на реальный вопрос.(

Ответы [ 5 ]

3 голосов
/ 14 декабря 2011

В ваших двух примерах вы на самом деле не определяете методы в Class или Module;вы определяете одноэлементные методы для объекта, который оказывается Class или Module, но может быть практически любым объектом.Вот пример с String:

Diff = "Use me to access really cool methods"

def Diff.patch
  # ...
end

. Вы можете сделать любое из них, и это будет работать, но лучший способ сгруппировать связанные методы - это Module как обычные методы экземпляра (т.е. безself.):

module Diff
  extend self  # This makes the instance methods available to the Diff module itself
  def diff ... # no self.
  def patch ...
end

Теперь вы можете:

  • использовать эту функциональность из любого класса (с include Diff) или из любого объекта (с extend Diff)
  • примером такого использования является строка extend self, которая позволяет вызывать Diff.patch.
  • , даже используя эти методы в глобальном пространстве имен

Например, в irb:

class Foo
  include Diff
end
Foo.new.patch # => calls the patch method
Diff.patch    # => also calls Diff.patch
include Diff  # => now you can call methods directly:
patch         # => also calls the patch method

Примечание : extend self «изменит» сам объект модуля Diff, но не повлияет на включениямодуля.То же самое происходит с def self.foo, foo не будет доступен ни одному классу, включая его.Короче говоря, только методы экземпляра Diff импортируются с include (или extend), а не синглтон-методами.Только наследование класса обеспечит наследование как экземпляров, так и одноэлементных методов.

Когда вы действительно хотите, чтобы включение модуля предоставляло и методы экземпляра, и одноэлементные методы, это не совсем легко.Вы должны использовать self.included крючок:

module Foo
  def some_instance_method; end

  module ClassMethods
    def some_singleton_method; end
  end

  def self.included(base)
    base.send :extend, ClassMethods
  end

  def self.will_not_be_included_in_any_way; end
end

class Bar
  include Foo
end
# Bar has now instance methods:
Bar.new.some_instance_method  # => nil
# and singleton methods:
Bar.some_singleton_method   # => nil
3 голосов
/ 14 декабря 2011

Основное различие между модулями и классами заключается в том, что вы не можете создать экземпляр модуля;Вы не можете сделать obj = MyModule.new.Предположение вашего вопроса состоит в том, что вы не хотите создавать какие-либо экземпляры, поэтому я рекомендую просто использовать модуль.

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

2 голосов
/ 14 декабря 2011

Модули Ruby используются для определения поведения, фрагментов связанных функций.

Классы Ruby используются для указания как состояния, так и поведения, единственного объекта.

Существует принцип в разработке программного обеспечения, который говорит, что код является ответственностью, поэтому используйте меньше кода. В случае с Ruby разница в строках кода равна cero. Таким образом, вы можете использовать любой способ (если вам не нужно сохранять состояние)

Если вы хотите быть пуристом, используйте модуль, поскольку вы не будете использовать функциональность State. Но я бы не сказал, что использовать класс неправильно.

Как общая информация: в Ruby класс является своего рода модулем.

http://www.ruby -doc.org / ядро-1.9.3 / Class.html

1 голос
/ 14 декабря 2011

По форме Модуль более корректен. Вы все еще можете создавать экземпляры класса, даже если он имеет только методы класса. Здесь вы можете представить модуль как статический класс C # или Java. Классы также всегда имеют методы, связанные с экземплярами (new, allocate и т. Д.). Используйте модуль. Методы класса обычно имеют отношение к объектам (создавая их, манипулируя ими). ​​

1 голос
/ 14 декабря 2011

Следующее также работает

Matrix = Object.new

def Matrix.add ...
def Matrix.equals ...

Это потому, что так называемые "методы класса" - это просто методы, добавленные к одному объекту, и на самом деле не имеет значения, что это за класс объекта.

...