善用 define_method

define_method 可以帮助我们动态的,快速的定义多个方法;比如有这样一个类:

class Post
  attr_accessor :title, :content, :state

  def initialize(title, content, state = :draft)
    @title, @content, @state = title, content, state
  end

  def draft
    @state = :draft
  end

  def posted
    @state = :posted
  end

  def deleted
    @state = :deleted
  end
end

draft posted deleted 分别用来把文章的状态设置为: 草稿 发表 和 删除 ,但是这三个方法看起来太类似了,而define_method 就可以帮助我们优化这部分代码:

class Post
  attr_accessor :title, :content, :state

  def initialize(title, content, state = :draft)
    @title, @content, @state = title, content, state
  end

  states = [:draft, :posted, :deleted]

  states.each do |state|
    define_method state do
      @state = state
    end
  end

这下就轻松多了吧!再来一个稍微复杂一点的例子,可以体现其灵活性:

class Game
  attr_accessor :name, :year, :system

  SYSTEMS = ['SNES', 'PS1', 'Genesis']

  SYSTEMS.each do |system|
    define_method "runs_on_#{system.downcase}?" do
      self.system = system.downcase
    end
  end
end

那么,如何在目标方法之后传递参数呢?比如说代理一个 block?

class Book
# 省略不相关代码

  [:each, :map, :select].each do |method|
    define_method method do |&block|
      books.send(method, &block)
    end
  end
end

方法体中之所以使用 send 方法,是因为在我们要重新定义的 each 方法里,books 需要委托数组方法 each 来处理 &block,而不是由 books 直接处理 █当然,其它两个方法也是这样的道理。最终 Ruby 帮我们生成的方法就是类似这样的:

def each # 这是我们为 Book 类定义的 each 方法
  books.each(&block) # 这是委托数组的 each 方法来帮 books 处理传入的 &block
end
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值