ruby 用类扩展对象

3gtaxfhh  于 2023-04-20  发布在  Ruby
关注(0)|答案(2)|浏览(104)

TL;DR:有没有一种方法可以将类(而不是模块)中的方法添加到单个对象中?
声明:1)我真的很想自己找到答案,但就是做不到。2)我曾经找到一个页面,展示了如何做到这一点,但要么我没有把它加入书签,要么我在我的(字面上)4,618个书签中找不到它。它与通过添加匿名类来改变方法的搜索顺序有关。
假设我有一个类,它有一堆方法,我想把这些方法添加到另一个类的一个示例中,有没有办法做到这一点?
我知道如何使用模块添加方法。例如,考虑以下场景:

# MyClass
class MyClass
    def method_a
        return 'this is method a'
    end
end

# ExtraMethods
module ExtraMethods
    def method_b
        return 'this is method b'
    end
end

# node
obj = MyClass.new()
puts obj.method_a # => this is method a

# add methods to object
obj.extend ExtraMethods

# call added method
puts obj.method_b # => this is method b

好吧,这是可行的。但是假设我希望ExtraMethods是一个类,而不是一个模块?我为什么要这样做?在我的真实的用例中,那些添加方法的类将被一次又一次地子类化。此外,这些子子类将由使用我将要发布的gem的人创建。我宁愿使用类继承的类似范例,而不是模块之间互相包含。
那么我该怎么做呢?填空:

# MyClass
class MyClass
    def method_a
        return 'this is method a'
    end
end

# ExtraMethods
class ExtraMethods
    def method_b
        return 'this is method b'
    end
end

# node
obj = MyClass.new()
puts obj.method_a # => this is method a

# add methods to object
# obj.extend ExtraMethods
YOUR_CODE_HERE

# call added method
puts obj.method_b # => this is method b
axzmvihb

axzmvihb1#

将方法添加到一个 * 特定 * 对象示例是不常见的。通常你在classinclude,它们会被添加到所有示例中。如果需要,你可以extend一个特定的示例,如果是这样,它基本上必须是一个module
这就是Ruby中的实现方式。这是一个简单的组合模式,与继承相反:

class MyClass
  include ExtraMethods
end

对于任何熟悉Ruby的人来说,用class扩展任何东西都会看起来很奇怪或不完整。

w3nuxt5m

w3nuxt5m2#

class MyClass
  def method_a
    'this is method a'
  end
end
module ExtraMethods
  def method_b
    'this is method b'
  end
end
obj1 = MyClass.new
  #=> #<MyClass:0x00007fe126afc7d8>
obj2 = MyClass.new
  #=> #<MyClass:0x00007fe126ae6d98>
obj1.method_a
  #=> "this is method a"
obj2.method_a
  #=> "this is method a"

您需要includeobj1的单例类中的模块ExtraMethods,这可以通过使用Object#extend来完成。

obj1.extend ExtraMethods
  #=>#<Class:#<MyClass:0x00007fe126afc7d8>>

这相当于

obj1.singleton_class.include ExtraMethods
obj1.singleton_class.instance_methods.grep /method_/
  #=> [:method_b, :method_a]
obj1.methods.grep /method_/
  #=> [:method_b, :method_a]
obj2.methods.grep /method_/
  #=> [:method_a]
obj1.method_b
  #=> "this is method b"
obj2.method_b
  #=> undefined method `method_b' for #<MyClass:0x00007fe126ae6d98>

相关问题