有没有办法将Ruby类初始化仅限制为子类?

时间:2012-11-26 17:42:38

标签: ruby

我正在创建一个支持API网络的库。该库的中心当前是每个API客户端子类的客户端类。由于我是编写所有API的人,因此它们的功能相似(通过access_token等进行restful,授权)。

但是,与其他ruby API客户端库(Twitter's等)不同,不应直接实例化客户端类。那是因为库不限于单个API。相反,每个API客户端都将子类化Client类。我的问题如下:

有没有办法要求只通过子类初始化Ruby类?

此外,在阅读this question时,我认为这里的课程比混音更好。

对于那些想要代码的人,这是一个例子:

class A
    def initialize(options = {})
        #what goes on in here doesn't really matter for the purpose of this question
        #I just don't want it to be initialized directly
        options.each do |k,v|
            instance_variable_set("@#{k}",v) unless v.nil?
        end
    end
end

class B < A
    attr_accessor :class_specific_opt
    def initialize( options = {} )
        @class_specific_opt = "val" unless options[:class_specific_opt].nil?
        super(options)
    end
end

有什么想法吗?

5 个答案:

答案 0 :(得分:2)

这里有类似抽象类的答案:How to implement an abstract class in ruby?, 虽然您可能仍然可以更好地将A作为模块提供并将其包含在其实现者中。

答案 1 :(得分:2)

你可以这样做:

class A
  def self.initialize_allowed?
    raise "You cannot initialize instances of this class."
  end

  def self.allow_initialize
    class << self
      def initialize_allowed?
        true
      end
    end
  end

  def initialize(options = {})
    self.class.initialize_allowed?
    options.each do |k,v|
      instance_variable_set("@#{k}", v)
    end
  end
end

调用A.new会引发RuntimeError并暂停initialize方法。然后,您可以通过调用initialized_allowed?来覆盖子类中的allow initialize方法。 (也许这有点矫枉过正,但我​​认为allow_initializedef self.initialize_allowed?;end更容易阅读:

class B < A
  allow_initialize
end

B.new #=> #<B:0x00000102837d10>

答案 2 :(得分:1)

如果您不想调用A.new,只需执行以下操作:

class <<A
  undef :new
end

然后,您将无法调用它:

A.new #=> NoMethodError: undefined method `new' for A:Class

答案 3 :(得分:0)

添加

private_class_method :new

到A级,

public_class_method :new

到B级。

答案 4 :(得分:0)

我认为最好的方法是制作新方法private。这正是ruby Singleton模块所做的。 Singleton Module Documentation

class A
  private_class_method :new
end

class B < A
  public_class_method :new
end