如何在初始化父类时返回子类的新实例?
给定一个类层次结构如下:
class A def initialize(param) if param == 1 then #initialize and return instance of B else #initialize and return instance of C end end end class B < A end class C < A end
初始化A
时是否可以实际初始化并返回B
或C
的实例? 即my_obj = A.new(param)
将导致my_obj
成为B
类或C
类的实例,具体取决于param
的值,该值在A.initialize(param)
进行检查。
在我的用例中,它在运行时只知道使用哪个子类( B
或C
)和父类( A
)基本上从未真正使用过。 我认为将B
或C
决定是否为共同祖先的逻辑可能是个好主意。
如果这是不可能的(或不好的风格),我应该在哪里检查param
和决定初始化哪个类?
你在这里打破了一个基本的OO原则 – 类应该对它们的子类一无所知。 当然,有时原则应该被打破,但没有明显的理由在这里做。
更好的解决方案是将实例化逻辑转换为单独类中的工厂方法。 工厂方法采用与上面A的初始化程序相同的参数,并返回相应类的实例。
问题是, initialize
的返回值被忽略。 这是你打电话给A.new
时发生的事情:
-
new
调用一个名为allocate
的特殊类方法 – 这将返回该类的空实例 -
new
然后调用initialize
对allocate
返回的对象,并返回该对象
要做你想做的事,你需要覆盖new
并使它做你想做的事:
class A def self.new(args*) if(args[0]==1) B.new(*args[1..-1]) else C.new(*args[1..-1]) end end end
还有一些事情要考虑。 如果A
本身从未真正使用过,那么你应该使用某种工厂方法,或者只是一个简单的if语句。 例如:
def B_or_C(param,args) (param == 1 ? B : C).new(args) end
设计实际上取决于您使用它们的方式。 例如,当你有一个可以用来处理某些东西的类时,例如HTML,你就可以有一个主类HTMLParser
,它可以覆盖new
并可以返回它的HTML1Parser
类: HTML1Parser
, HTML2Parser
, HTML3Parser
, HTML4Parser
和HTML5Parser
。
注意:您必须将new
方法重写为子类中的默认值以防止无限循环:
def self.new(args*) obj=allocate obj.send(:initialize, *args) obj end