如何在初始化父类时返回子类的新实例?

给定一个类层次结构如下:

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时是否可以实际初始化并返回BC的实例? 即my_obj = A.new(param)将导致my_obj成为B类或C类的实例,具体取决于param的值,该值在A.initialize(param)进行检查。

在我的用例中,它在运行时只知道使用哪个子类( BC )和父类( A )基本上从未真正使用过。 我认为将BC决定是否为共同祖先的逻辑可能是个好主意。

如果这是不可能的(或不好的风格),我应该在哪里检查param和决定初始化哪个类?

你在这里打破了一个基本的OO原则 – 类应该对它们的子类一无所知。 当然,有时原则应该被打破,但没有明显的理由在这里做。

更好的解决方案是将实例化逻辑转换为单独类中的工厂方法。 工厂方法采用与上面A的初始化程序相同的参数,并返回相应类的实例。

问题是, initialize的返回值被忽略。 这是你打电话给A.new时发生的事情:

  • new调用一个名为allocate的特殊类方法 – 这将返回该类的空实例
  • new然后调用initializeallocate返回的对象,并返回该对象

要做你想做的事,你需要覆盖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类: HTML1ParserHTML2ParserHTML3ParserHTML4ParserHTML5Parser

注意:您必须将new方法重写为子类中的默认值以防止无限循环:

 def self.new(args*) obj=allocate obj.send(:initialize, *args) obj end