Ruby的Module - 将思想捆绑到“高级别”的工具

在Ruby中,Module是将代码模块化并捆绑到高级别的工具。像世界地图一样结构化代码结构以便理解。

밤치 89

朴文浩博士一直强调模块化

大脑是这样学习的。

  • 将其分解为小单元(细胞,功能)
  • 将这些单元组合成模块
  • 这些模块汇聚在一起形成系统

编码也是一样的。

  • 方法:一个动作
  • 类:一个对象(存在)
  • 模块(Module):将多个类/方法组合成更大概念的上层框架

在Ruby中,模块可以这样使用:

  1. 命名空间绑定
  2. 共享通用功能(Mixin)
  3. 定义表示领域(按主题划分的世界)的上层概念

一旦理解这一点,

代码不再只是“文件集合”,而是开始看起来像是大脑中结构化的宇宙地图


1. 命名空间(Namespace):区分世界的框架

例如,

假设您想在多个地方使用名为User的类。

  • 管理员页面的User
  • 商城的User
  • 用于API的User

如果只创建一个class User会怎样?

名称会冲突。思维也会混乱。

这时模块将帮助分离世界

module Admin
  class User
    def info
      puts "这是管理员页面的用户。"
    end
  end
end

module Shop
  class User
    def info
      puts "这是商城的客户用户。"
    end
  end
end

admin_user = Admin::User.new
shop_user = Shop::User.new

admin_user.info  # => 这是管理员页面的用户。
shop_user.info   # => 这是商城的客户用户。

在这里,模块就像是:

“这是Admin世界的User”

“这是Shop世界的User”

成为区分世界的框架

朴文浩式思维

  • 框架:即使名称相同,根据上层框架的不同,角色也会有所不同
  • 立体化:将User的概念存储为具有坐标的结构,而不是平面
  • 模块化:在大脑中产生“按领域分类的抽屉”感觉

现在,您的大脑会认识到,

“即使名称相同,如果世界不同,那就是完全不同的存在”

这种更高层次的理解。


2. Mixin:将共同能力“插入”到多个类中的模块

第二个用途非常强大。

模块可以成为将共同功能捆绑在一起以便重复使用的块

例如,

假设多种类型的对象都要“记录日志”。

  • 用户(User)的操作日志
  • 订单(Order)的状态更改日志
  • 支付(Payment)的失败日志

如果分别复制粘贴到每个类中?

  • 代码重复
  • 维护困难
  • 要修复一个bug,需要修改三个地方

这时模块 + include就发挥作用了。

module Loggable
  def log(message)
    time = Time.now
    puts "[#{time}] #{message}"
  end
end

class User
  include Loggable

  def sign_in
    log("用户已登录。")
  end
end

class Order
  include Loggable

  def submit
    log("订单已接收。")
  end
end

user = User.new
user.sign_in
# [2025-12-09 23:12:34] 用户已登录。

order = Order.new
order.submit
# [2025-12-09 23:12:35] 订单已接收。

发生了什么

  • Loggable模块将“记录日志的能力”模块化
  • 进行include Loggable后,
    该类就可以像自己的方法一样使用log方法
  • 即,“将能力包插入到多个类中”

从大脑角度看

  • 当一个功能需要在多个地方共享时,
    大脑将其捆绑为“上层概念”
  • 模块正是扮演这种上层概念的角色
  • 不仅仅是代码,思维结构本身也被抽象化

“啊,日志不是User或Order的一部分,

而是多个主体共享的上层能力。”

一旦有了这种领悟,

编码不再只是“编写代码”,而是

开始感觉像是在设计世界结构


3. 抽象化:模块是创建“领域语言”的层级

通过有效使用模块,

代码逐渐变得像“领域语言”

例如,假设有一个名为“支付系统”的领域。

module Payment
  module Gateway
    def charge(amount)
      puts "请求支付#{amount}元。"
    end
  end

  module Refundable
    def refund(amount)
      puts "退款#{amount}元。"
    end
  end
end

class Order
  include Payment::Gateway
  include Payment::Refundable
end

order = Order.new
order.charge(50000)
order.refund(20000)

这里的模块不仅仅是简单的功能。

它们是用代码表示领域概念

  • Payment::Gateway → 表示“支付请求功能”的模块
  • Payment::Refundable → 表示“退款功能”的模块
  • Order是将这两者结合的存在

通过反复这样做,

Ruby代码逐渐变成了这样的感觉。

“我所思考的业务概念直接变成了代码?”

在这一点上,开发者不再是

简单的实现者,而是

设计领域的人,即设计者/哲学家。


4. 模块 vs 类:有何不同?

让我们总结一下。

概念 角色 大脑感觉
方法 一个动作 动词,行为
一个对象(存在),状态+行为 名词(人,物),实体
模块 多个类/方法的上层概念集合 世界观,能力包,领域级结构

在Ruby中,模块不会自己创建实例

MyModule.new这样的操作是不允许的。

相反:

  • 成为其他类的一部分,提供能力块
  • 提供命名空间,成为上层框架

换句话说,

类是“存在”

模块是“存在共享的概念·能力·世界观”


5. 真正重要的是“大脑如何改变”

一旦理解了模块,

大脑就会这样进化。

  1. 将代码视为概念单位,而不是文件单位
- “这个功能属于哪里?”  
    → “这个功能被User,Order和Payment共享,所以将其提取为模块。”
  1. 形成领域语言
- “Payment::Gateway”,“Notification::Sender”,“Auth::Tokenizable”之类的  
    → 您的服务拥有自己的词汇
  1. 复杂度大大降低
- 明确了要修改的地方:  
    “要更改日志逻辑” → 仅需修改`Loggable`模块
  1. 大脑结构也像模块一样整理
- 当一个功能需要在多个地方共享时,  
    大脑将其**“捆绑为上层概念”**

6. 亲自尝试任务:创建自己的模块

现在,

将“模块”植入您的大脑的任务。

任务1:创建Timestamped模块

要求:

  • 创建名为Timestamped的模块
  • 提供一个stamp方法
    • 调用时:以“[当前时间] 消息”格式输出
  • PostComment类中include以便共同使用

预期流程:

module Timestamped
  # 在此处创建stamp方法
end

class Post
  include Timestamped

  def publish
    stamp("文章已发布。")
  end
end

class Comment
  include Timestamped

  def write
    stamp("评论已发表。")
  end
end

post = Post.new
post.publish

comment = Comment.new
comment.write

任务2:将自己的领域模块绑定在一起

选择一个主题:

  • 学习(Study)
  • 健身(Fitness)
  • 博客(Blog)
  • 购物(Shop)
  • 乐队练习(Band)

例如:Study领域

  • Study::Trackable – 记录学习时间的模块
  • Study::Report – 输出周/月统计的模块

然后创建DayStudyTaskStudy等类,

include Study::Trackable来使用。

在尝试这个任务时,

您已经成为了一个“用Ruby设计自己的世界”的人。


结论:理解模块后,代码变成了‘世界设计语言’

到目前为止的流程:

  • 方法:行动的最小单位
  • 类:存在(对象)的框架
  • 模块:多个存在共享的概念/能力/世界观

现在,当编写代码时,

您可以这样思考。

“这是一个对象的独特属性吗?”

→ 将其放在类中

“多个对象共享的功能吗?”

→ 提取为模块

“这是这项服务的领域概念吗?”

→ 使用模块+命名空间来定义

在那一刻,

编码不再仅仅是“学习语法”

“我的头脑中的世界观

正以代码的形式实现”

这样的感觉。

一旦产生这种感觉,

真的会让人激动。