我可以在自己的方法中更改对象的类型吗?

时间:2014-10-25 02:40:02

标签: ruby object type-conversion

如果我可以在自己的方法中更改对象的类,那将会很棒:

class Dog < Animal
  def initialize(color, size)
    #do some stuff
  end
  def do_lots_of_stuff
    #really long involved calculations with different classes and methods 
    #and objects that I can't really change at this point
    if random_condition
      self = Super_Special_Dog.new(@color, @size, specialness)
    end
  end
end

class Super_Special_Dog < Dog
  def initialize(color, size, specialness)
    #do stuff
  end
end

有没有办法将Dog的实例,比如说fido&#39;转换为Super_Special_Dog,以便在调用fido.do_lots_of_stuff之后fido.is_a? Super_Special_Dog将返回true,其他方法/类可以使用Super_Special_Dog的方法和变量对fido进行操作吗?

我尝试了上述结构并收到错误Can't change the value of self (SyntaxError)。我可以根据Super_Special_DogDog根据我的需要制作Animal

我可以看到一些关于将对象转换为自己的方法之外的其他问题,但我需要在内部进行。我已经有大约2k-3k的代码行交织在一起,此时很难改变。

2 个答案:

答案 0 :(得分:2)

首先,没有人应该关心fido是Dog还是Super_Special_Dog - 他们应该只关心fido能做什么技巧(也就是说,他回答的是什么方法)。这是鸭子打字(狗打字?)做事的方式。

如果删除了需要更改实际类的要求,那么从内部向实例添加新功能是微不足道的。

class Dog
  def become_special
    @special = true
    extend SpecialTraits
  end
end

module SpecialTraits
  def do_special_thing
  end
end

fido = Dog.new
rex = Dog.new

fido.become_special

fido.do_special_thing # Okay!
rex.do_special_thing # NoMethodError

答案 1 :(得分:1)

TL; DR

您无法更改对象的类,但可以混合使用其他模块和方法。有很多方法可以做到这一点;一种方法是通过向单个实例添加单例方法。

实例上的动态单例方法

您可以使用Object#define_singleton_method在特定实例上动态定义方法。例如:

class Dog; end

rover = Dog.new
spot  = Dog.new
fido  = Dog.new

# Give Rover and Spot a new method dynamically.
[rover, spot].each do |dog|
  dog.define_singleton_method(:bark) { 'Woof! Woof!' }
end

# Only Rover and Spot have the new method; Fido is a barkless dog.
[rover, spot, fido].map { |dog| dog.respond_to? :bark }
#=> [true, true, false]