我正在创建一个支持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
有什么想法吗?
答案 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_initialize
比def 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