设计Ruby API时的类与模块?

时间:2010-11-02 04:41:53

标签: ruby api design-patterns inheritance composition

当我阅读有关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 个答案:

答案 0 :(得分:5)

如果您的API提供了将由客户端扩展的基本功能,那么您应该更喜欢继承

如果您的API将使用自己的基本功能扩展各种客户端,那么您应该选择合成

答案 1 :(得分:2)

你有很多围绕这个问题的理论。

我倾向于选择合成,因为它使行为更加可重用,但是如果你看看Rails,你每次想要数据库中的对象时都必须继承ActiveRecord :: Base类。如果你看一下DataMapper,那就相反了,因为他们只需要你包含DataMapper :: Resource。

继承与组合(通过模块)是一个很大的主题,您必须问自己的问题将归结为:如何实现我提供的组件与另一个用户现有代码库之间的更大解耦?

答案 2 :(得分:1)

Ruby仅支持单继承。因此,如果API客户端必须继承您的基类,则它们将无法继承其他类。使用模块包含可以使代码成为:

class Student < Person
  include Base
  has_many :books
end

因此你可以“继承”Person和Base。

然而,经典的继承语法看起来更自然,更少“神奇”