Ruby子类如何修改父类内部类且不影响其他子类实例
这个问题我之前也碰到过,核心问题出在Base类的initialize方法硬编码了Base::Child.new——不管子类有没有定义自己的内部Child类,实例化时都会直接调用父类的Base::Child,而修改Base::Child又会污染所有子类。下面给你两种可行的解决方案:
方案1:修改Base类(推荐,扩展性更强)
咱们可以让Base动态地获取当前实例所属类的Child,而不是固定死用Base::Child。只需要把initialize里的Base::Child.new改成self.class::Child.new就行:
class Base class Child def im "from base child" end end def initialize # 用self.class获取当前实例的类,再找对应的Child @child = self.class::Child.new end def test @child.im end end
然后子类B正常定义自己的内部Child类就行:
class B < Base class Child def im "from b child" end end end class A < Base # 不需要额外修改 end
测试一下:
puts A.new.test # 输出 "from base child" puts B.new.test # 输出 "from b child"
原理很简单:当实例是A的时候,self.class就是A,A没有自己的Child类,会自动继承Base::Child;当实例是B的时候,self.class是B,就会用B自己定义的Child类。
方案2:不修改Base类,在子类B中重写initialize
如果你没办法修改Base类(比如它是第三方库的代码),可以在子类B里重写initialize方法,直接替换@child为自己的Child实例:
class Base class Child def im "from base child" end end def initialize @child = Child.new end def test @child.im end end class B < Base class Child def im "from b child" end end def initialize # 先调用父类的initialize,保留原有逻辑 super # 替换@child为自己的Child实例 @child = Child.new end end class A < Base # 不需要额外修改 end
测试结果和方案1完全一致:
puts A.new.test # 输出 "from base child" puts B.new.test # 输出 "from b child"
这种方式的好处是不需要动父类代码,但如果Base的initialize有其他重要逻辑,一定要记得先调用super执行父类的初始化,再替换@child。
内容的提问来源于stack exchange,提问作者kukrt
相关产品推荐
相关产品推荐

