用 Block 重构代码的几种方法

简介: 用 Block 重构代码的几种方法

Ruby 中 block 是非常重要的,也是非常特别的一部分内容。 很多代码的重构都可以通过 code block 得以一种优雅的方式实现。 根据《Ruby 最佳实践》中的内容,我简单做一些小结。

首先,最常见的就是用于遍历。

(1..5).to_a.map { |i| i * 2 }
class SortedList
  def initialize
    @data = []
  end
  def <<(element)
    (@data << element).sort!
  end
  def each
    @data.each { |e| yield(e) }
  end
end

其次,用于在方法的预处理和后处理操作中插入代码

File.open("some.txt") { |f| f << "some words" }

有时也用于临时提升变量的可见范围(scope)(在元编程中比较常见)

"This is a string".instance_eval do
  "O hai, can has reverse? #{ revers }. kthxbye"
end
#=> "O hai, can has reverse? gnirts a si sihT. kthsbye"

最后,就是作为模板

>> foo = Hash.new { |h, k| h[k] = [] }
=> {}
>> foo[:bar]
=> []
>> foo[:bar] << 1 << 2 << 3
=> [1, 2, 3]

用 Block 重构代码的几个范例

用 block 来重构 Pre 和 Post 处理过程

require "socket"
class Client
  def initialize(ip = "127.0.0.1", port = 3333)
    @ip, @port = ip, port
  end
  def send_message(msg)
    socket = TCPSocket.new(@ip, @port)
    socket.puts(msg)
    response = socket.gets
  ensure
    socket.close if socket
  end
  def receive_message
    socket = TCPSocket.new(@ip, @port)
    response = socket.gets
  ensure
    socket.close if socket
  end
end

这个代码明显不符合 DRY 的风格,所以利用 block 来重构一下:

require "socket"
class Client
  def initialize(ip = "127.0.0.1", port = 3333)
    @ip, @port = ip, port
  end
  def send_message(msg)
    connection do |socket|
      socket.puts(msg)
      socket.gets
    end
  end
  def receive_message
   connection { |socket| socket.gets }
  end
  private
  def connetcion
    socket = TCPSocket.new(@ip, @port)
    yield(socket)
  ensure
    socket.close if socket
  end
end
if __FILE__ == $0
  client = Client.new
  ["Hello", "My name is Greg", "Goodbye"].each do |msg|
    response = client.send_message(msg)
    puts response
  end
end
#输出以下内容
#Hello from server at Wed Jul 23 16:15:37 ...
#Nice to meet you Greg!
#Goodbye from server at Wed Jul 32 ...

以上代码明显简洁了很多

用于动态回调

require 'socket'
class Server
  def initialize(port = 3333)
    @server = TCPServer.new("127.0.0.1", port)
    @handlers = {}
  end
  def handle(pattern, &block)
   @handlers[pattern] = block
  end
  def run
    while session = @server.accept
      msg = session.gets
      match = nil
      @handlers.each do |pattern, block|
        if match = msg.match(pattern)
          break session.puts(block.call(match))
        end
        unless match
          session.puts "Server received unknown message: #{msg}"
        end
      end
    end
  end
end
if __FILE__ == $0
  server = Server.new
  server.handle(/hello/i){ "Helllo from server at #{Time.now}" }
  server.handle(/goodbye/i){ "Goodbye from server at #{Time.now}" }
  server.handle(/name is (\w+)/){ |m| "Nice to meet you #{m[1]}!" }
  server.run
end

用于简化接口

server = Server.new
server.handle(/hello/i){ "Helllo from server at #{Time.now}" }
server.handle(/goodbye/i){ "Goodbye from server at #{Time.now}" }
server.handle(/name is (\w+)/){ |m| "Nice to meet you #{m[1]}!" }
server.run
#这段代码可以简化为以下版本
Server.run do
  handle(/hello/i){ "Helllo from server at #{Time.now}" }
  handle(/goodbye/i){ "Goodbye from server at #{Time.now}" }
  handle(/name is (\w+)/){ |m| "Nice to meet you #{m[1]}!" }
end
#class Server修改如下
class Server
  #other methods same as before
  #声明为类方法
  def self.run(port=3333, &block)
    server = Server.new(port)
    #使用instance_eval和&block来重构代码
    server.instance_eval(&block)
    server.run
  end
end


相关文章
重构——10搬移函数(Move Method)
搬移函数(Move Method):你的程序中,有个函数与其所驻类之外的另一个类进行更多的交流:调用后者,或者被后者调用。在该函数最常引用的类中建立一个有着类似行为的新函数。将就函数变成一个单纯的委托函数,或是将旧函数完全移除
3554 0
|
2月前
|
JSON 前端开发 Java
代码的应用重构问题之BaseActivity类的主要功能问题如何解决代码缩减的主要问题如何解决
代码的应用重构问题之BaseActivity类的主要功能问题如何解决代码缩减的主要问题如何解决
|
2月前
|
数据库
代码的应用重构问题之BaseActivity类的主要功能问题如何解决
代码的应用重构问题之BaseActivity类的主要功能问题如何解决
|
2月前
|
存储 数据库
cannot read properties of underfined (reading ‘code‘),别光知道抄,有的时候,细节就是影响全局关键,别人代码到你项目不一定100%正确,判断bug出
cannot read properties of underfined (reading ‘code‘),别光知道抄,有的时候,细节就是影响全局关键,别人代码到你项目不一定100%正确,判断bug出
|
4月前
|
测试技术 数据处理 数据库
关于在 ABAP 中使用 PACKAGE SIZE 进行分块读写,块大小具体维护成多少比较合适?
关于在 ABAP 中使用 PACKAGE SIZE 进行分块读写,块大小具体维护成多少比较合适?
|
4月前
|
前端开发 开发者
【专栏】BEM(Block-Element-Modifier)是一种前端命名规范和架构方法,旨在创建清晰、可维护的代码结构。
【4月更文挑战第29天】BEM(Block-Element-Modifier)是一种前端命名规范和架构方法,旨在创建清晰、可维护的代码结构。它包括Block(独立功能单元)、Element(Block的子元素)和Modifier(表示状态或变体)。BEM的特点包括命名一致性、模块化设计、清晰结构和可复用性,适用于代码组织、样式管理、组件化开发和团队协作。虽然命名较长和学习成本是其局限性,但BEM在提升代码质量和效率方面具有显著优势,是前端开发的重要工具。
95 0
|
前端开发 开发者
will-change 属性细节太多了,一般人玩不好
will-change 被定义为浏览器最后的优化手段,它的作用是告诉浏览器,这个元素将要发生变化,浏览器可以提前做一些准备工作,当元素发生变化时,浏览器就不需要再做一些额外的工作,从而提高性能。
212 0
will-change 属性细节太多了,一般人玩不好
|
设计模式 存储 SQL
【Java设计模式 规范与重构】 五 重构实战:基于ID生成器case(上)
【Java设计模式 规范与重构】 五 重构实战:基于ID生成器case(上)
119 0
|
设计模式 存储 Java
【Java设计模式 规范与重构】 五 重构实战:基于ID生成器case(下)
【Java设计模式 规范与重构】 五 重构实战:基于ID生成器case(下)
192 0
|
设计模式 Java
【Java设计模式 规范与重构】 一 重构的目的、内容、时机、方法
【Java设计模式 规范与重构】 一 重构的目的、内容、时机、方法
170 0