Класс против модуля в разработке Ruby API? - PullRequest
7 голосов
/ 02 ноября 2010

Когда я читал больше о метапрограммировании Ruby, большую часть времени мы находили как минимум два решения для решения проблемы. Пожалуйста, посмотрите на два примера ниже:

class Base
  def self.has_many(*args)
    # ...
  end
end

class Student < Base
  has_many :books
end

Другой стиль:

module Base
  def self.included(klass)
    klass.extend ClassMethods
  end

  module ClassMethods
    def has_many(*args)
      # ...
    end
  end
end

class Student
  include Base

  has_many :books
end

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

Ответы [ 3 ]

5 голосов
/ 02 ноября 2010

Если ваш API предоставляет базовую функциональность, которая будет расширена клиентом, тогда вы должны предпочесть наследование .

Если ваш API собирается расширять различные клиенты с их собственной базовой функциональностью, тогда вам следует выбрать состав .

2 голосов
/ 02 ноября 2010

У вас есть много теорий вокруг этого вопроса.

Я предпочитаю композицию, потому что она делает поведение намного более пригодным для повторного использования, но если вы посмотрите на Rails, вам придется создавать подкласс ActiveRecord :: Base class каждый раз, когда вы хотите использовать объект в вашей базе данных. Если вы посмотрите на DataMapper, то все наоборот, поскольку вам просто нужно включить DataMapper :: Resource.

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

1 голос
/ 02 ноября 2010

Ruby поддерживает только одиночное наследование. Поэтому, если клиент API должен наследовать ваш базовый класс, он теряет способность наследовать другие классы. Используя включение модуля, вы создаете код наподобие:

class Student < Person
  include Base
  has_many :books
end

И, таким образом, вы можете «наследовать» как Личность, так и Основу.

Однако классический синтаксис наследования выглядит более естественным и менее "волшебным"

...