如何在父母 class 中打开 class 而不影响 ruby 中的其他 sub-classed 实例
how do you open a class in parental class without affecting to other sub-classed instances in ruby
假设你有这个 Base class 你需要扩展。
class Base
class Child
def im
"from base child"
end
end
def initialize
@child = Child.new
end
def test
@child.im
end
end
对于常规情况,您只需要扩展 Base class 并为其 class 添加方法。
class A < Base
# add methods
end
但是,如果 sub-class 想像这样改变父母内部 class 的行为,这是行不通的。我认为这是因为 Base#initialize 调用了 Child.new
。 (不是 B 调用)
class B < Base
class Child
def im
"from b child"
end
end
end
puts B.new.test # "from base child"
如果我更改为 class Base::Child
,其他 sub-class 个实例将受到影响。
class B < Base
class Base::Child
def im
"from b child"
end
end
end
puts A.new.test # "from b child"
puts B.new.test # "from b child"
如果我想让A和B表现得像下面这样,我应该如何打开class B中的内部class? (或者我应该在 Base 中进行更改吗?)
class B < Base
class ????? Child
def im
"from b child"
end
end
end
puts A.new.test # "from base child"
puts B.new.test # "from b child"
我想我明白了。 Base 应该调用 self.class::
到 Child.new 调用
class Base
class Child
def im
"from base child"
end
end
def initialize
@child = self.class::Child.new
end
def test
@child.im
end
end
class A < Base
end
class B < Base
class Child
def im
"from b child"
end
end
end
puts A.new.test
puts B.new.test
你想做的事情在 Ruby 中非常不寻常,因为嵌套的 classes 不是继承的。
当您执行以下操作时
class B < Base
class Child
end
end
有两种可能性:要么从 Base
中得到 Child
,要么 Child
未找到并被视为新常量。在这种情况下,Ruby 实际上将 Child
视为一个新常量(我猜测是为了防止意外猴子修补父 class 中的 Child
)所以你不是完全打开 Base::Child
,您正在定义一个完全独立的 class!试试吧:
B::Child == Base::Child
# false!
如果它们相等,这就是您通过指定 Base::Child
得到的结果,您会遇到您在问题中指出的问题:修改 subclass 中的 Child
会将其修改为所有子classes。但同样,这是意料之中的,因为 嵌套 class 不是继承的 。要么只有一个 Child
所有子class 共享,要么每个 class 都有自己的 Child
,与 Base::Child
.[=25= 完全无关]
然而,通过使用元编程和 inherited
钩子,可以使嵌套的 classes 继承。就像我说的,这是非常规的,所以它可能会让阅读您的代码的其他 Rubyists 感到奇怪。但如果你真的需要这样做,方法如下:
class Base
class Child
def im
"from base child"
end
def common
"shared by all subclasses"
end
end
def self.inherited subclass
# define a new Child class that inherits from Base::Child
subclass.const_set "Child", Class.new(self::Child)
end
def initialize
@child = self.class::Child.new
end
def test
puts @child.im
puts @child.common
end
end
class A < Base
# now this is opening Child, but not Base::Child! Rather A::Child < Base::Child
class Child
def im
"from a child"
end
end
end
class B < Base
# same here, opening a subclass of Base::Child so we can make changes but still share behavior with Base::Child
class Child
def im
"from b child"
end
end
end
A.new.test
# from a child
# shared by all subclass
B.new.test
# from b child
# shared by all subclasses
假设你有这个 Base class 你需要扩展。
class Base
class Child
def im
"from base child"
end
end
def initialize
@child = Child.new
end
def test
@child.im
end
end
对于常规情况,您只需要扩展 Base class 并为其 class 添加方法。
class A < Base
# add methods
end
但是,如果 sub-class 想像这样改变父母内部 class 的行为,这是行不通的。我认为这是因为 Base#initialize 调用了 Child.new
。 (不是 B 调用)
class B < Base
class Child
def im
"from b child"
end
end
end
puts B.new.test # "from base child"
如果我更改为 class Base::Child
,其他 sub-class 个实例将受到影响。
class B < Base
class Base::Child
def im
"from b child"
end
end
end
puts A.new.test # "from b child"
puts B.new.test # "from b child"
如果我想让A和B表现得像下面这样,我应该如何打开class B中的内部class? (或者我应该在 Base 中进行更改吗?)
class B < Base
class ????? Child
def im
"from b child"
end
end
end
puts A.new.test # "from base child"
puts B.new.test # "from b child"
我想我明白了。 Base 应该调用 self.class::
到 Child.new 调用
class Base
class Child
def im
"from base child"
end
end
def initialize
@child = self.class::Child.new
end
def test
@child.im
end
end
class A < Base
end
class B < Base
class Child
def im
"from b child"
end
end
end
puts A.new.test
puts B.new.test
你想做的事情在 Ruby 中非常不寻常,因为嵌套的 classes 不是继承的。
当您执行以下操作时
class B < Base
class Child
end
end
有两种可能性:要么从 Base
中得到 Child
,要么 Child
未找到并被视为新常量。在这种情况下,Ruby 实际上将 Child
视为一个新常量(我猜测是为了防止意外猴子修补父 class 中的 Child
)所以你不是完全打开 Base::Child
,您正在定义一个完全独立的 class!试试吧:
B::Child == Base::Child
# false!
如果它们相等,这就是您通过指定 Base::Child
得到的结果,您会遇到您在问题中指出的问题:修改 subclass 中的 Child
会将其修改为所有子classes。但同样,这是意料之中的,因为 嵌套 class 不是继承的 。要么只有一个 Child
所有子class 共享,要么每个 class 都有自己的 Child
,与 Base::Child
.[=25= 完全无关]
然而,通过使用元编程和 inherited
钩子,可以使嵌套的 classes 继承。就像我说的,这是非常规的,所以它可能会让阅读您的代码的其他 Rubyists 感到奇怪。但如果你真的需要这样做,方法如下:
class Base
class Child
def im
"from base child"
end
def common
"shared by all subclasses"
end
end
def self.inherited subclass
# define a new Child class that inherits from Base::Child
subclass.const_set "Child", Class.new(self::Child)
end
def initialize
@child = self.class::Child.new
end
def test
puts @child.im
puts @child.common
end
end
class A < Base
# now this is opening Child, but not Base::Child! Rather A::Child < Base::Child
class Child
def im
"from a child"
end
end
end
class B < Base
# same here, opening a subclass of Base::Child so we can make changes but still share behavior with Base::Child
class Child
def im
"from b child"
end
end
end
A.new.test
# from a child
# shared by all subclass
B.new.test
# from b child
# shared by all subclasses