ZetCode

Ruby extend 方法

最后修改日期:2025 年 4 月 27 日

本教程解释了如何使用 Ruby 的 extend 方法将模块功能添加到对象。extend 方法是一种在对象级别混入模块方法的强大方式。

extend 方法将模块方法添加到接收者的单例类。与影响实例的 include 不同,extend 作用于单个对象。这使得灵活的对象增强成为可能。

扩展方法将作为扩展对象上的实例方法提供。这项技术对于向特定对象添加功能而不影响其类非常有用。可以按顺序扩展多个模块。

基本 extend 示例

这个简单的例子演示了如何使用模块方法扩展对象。这些方法仅在该特定对象上可用。

basic_extend.rb
module Greeter
  def greet
    "Hello from #{self}"
  end
end

obj = Object.new
obj.extend(Greeter)

puts obj.greet

extend 方法将 Greeter 模块方法添加到 obj。现在 obj 可以调用 greet,即使它的类不包含此方法。同一类的其他对象将没有此方法。

扩展类对象

由于类在 Ruby 中是对象,我们可以用模块方法扩展它们。这使得这些方法作为类方法而不是实例方法可用。

extend_class.rb
module ClassMethods
  def class_info
    "Class name: #{name}"
  end
end

class MyClass
  extend ClassMethods
end

puts MyClass.class_info

在这里,extendclass_info 添加为 MyClass 的类方法。这是添加类级别功能的常见模式。该方法对类本身可用。

多模块扩展

可以将多个模块扩展到一个对象。方法按扩展顺序添加,在发生冲突时,后扩展的模块具有优先权。

multiple_modules.rb
module A
  def identify
    "From module A"
  end
end

module B
  def identify
    "From module B"
  end
end

obj = Object.new
obj.extend(A, B)

puts obj.identify

输出显示了 Bidentify 版本,因为它是最后扩展的。当方法名称相同时,扩展顺序很重要。这演示了方法查找的优先级。

在类中扩展

extend 方法可以在类定义中使用,将模块方法添加到类对象本身。这与 include 不同。

class_extension.rb
module InstanceMethods
  def instance_identify
    "Instance method"
  end
end

module ClassMethods
  def class_identify
    "Class method"
  end
end

class MyClass
  include InstanceMethods
  extend ClassMethods
end

puts MyClass.class_identify
puts MyClass.new.instance_identify

这个例子展示了 includeextend 之间的区别。include 添加实例方法,而 extend 添加类方法。两者在不同场景下都有用。

动态扩展

对象可以在运行时动态扩展。这允许基于程序条件进行灵活的对象行为修改。

dynamic_extension.rb
module AdminFeatures
  def admin_action
    "Performing admin action"
  end
end

module UserFeatures
  def user_action
    "Performing user action"
  end
end

class User
  attr_accessor :role
end

user = User.new
user.role = :admin

user.extend(AdminFeatures) if user.role == :admin
user.extend(UserFeatures) if user.role == :user

puts user.admin_action if user.role == :admin

用户对象根据其角色扩展了不同的模块。这种模式无需子类化即可实现特定角色的功能。这些方法仅存在于需要它们的对象上。

扩展核心对象

Ruby 的核心对象可以用自定义方法进行扩展。这应该谨慎进行,以避免冲突和混淆。

core_extension.rb
module StringExtensions
  def shout
    upcase + "!"
  end
end

str = "hello world"
str.extend(StringExtensions)

puts str.shout
puts "another string".respond_to?(:shout) # false

只有特定的 str 对象获得了 shout 方法。其他字符串不受影响。这比直接 monkey-patching String 类更安全。它限制了更改的范围。

Extend 与 Include

这个例子对比了 extendinclude,以阐明它们不同的行为。它们服务于相关但不同的目的。

extend_vs_include.rb
module SharedMethods
  def identify
    "From SharedMethods"
  end
end

class ExtendedClass
  extend SharedMethods
end

class IncludedClass
  include SharedMethods
end

puts ExtendedClass.identify
puts IncludedClass.new.identify

ExtendedClassidentify 作为类方法,而 IncludedClass 将其作为实例方法。这说明了这两种混入模块功能的方法之间的关键区别。

来源

Ruby Module#extend 文档

本教程通过实际示例涵盖了 Ruby 的 extend 方法,展示了对象扩展、类方法和动态行为修改。

作者

我叫 Jan Bodnar,我是一名热情的程序员,拥有丰富的编程经验。我从 2007 年开始撰写编程文章。迄今为止,我已撰写了 1400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出 所有 Ruby 教程