【问题标题】:Can this ruby method be refactored?这个 ruby​​ 方法可以重构吗?
【发布时间】:2015-08-15 10:03:13
【问题描述】:

一个user有多个libraries,每个库有多个books。我想知道用户是否在他的图书馆中有一本书。我调用这个方法是:current_user.has_book?(book):

def has_book?(book)
  retval = false
  libraries.each do |l|
    retval = true if l.books.include?(book)
  end
  return retval
end

我的方法可以重构吗?

【问题讨论】:

  • 出于什么目的?你最终的目标是什么?如果清晰是您的目标,则较短不一定更清晰。
  • 我的目的是采用和理解我使用的语言的“技巧和窍门”,以生成更易于维护的代码并保持与常见用法一致。如果我能在 1 或 2 内完成这项工作,我不想要丑陋的代码或 10 行代码。
  • 在 Ruby 中,您始终可以用分号替换换行符,因此您始终可以在 1 行中完成这项工作:def has_book?(book) retval = false; libraries.each do |l| retval = true if l.books.include?(book) end; return retval end。不过,这并不一定会使它更易于维护。 (旁注:我真的不理解对“少行”或“单行”的痴迷。)
  • 可维护性和......呃......“惯用性”?我的意思是,您的最终目标是拥有可维护和惯用的代码。那么你显然需要重构。您最近的编辑似乎正在解决这个问题。
  • 我想知道为什么@Зелёный 删除了他的答案,它似乎确实回答了这个问题,它甚至大大提高了性能。

标签: ruby-on-rails ruby refactoring


【解决方案1】:
def has_book?(book)
    libraries.any?{|lib| lib.books.include?book}
end

几乎是我能想象到的最简单的。 虽然不是 Nil 安全的。

【讨论】:

    【解决方案2】:
    def has_book?(book)
      libraries.map { |l| l.books.include?(book) }.any?
    end
    

    map 将库对象集合转换为布尔集合,具体取决于它们是否包含书籍,如果数组中的任何元素为 trueany? 将返回 true

    这行数更少,但如果您在找到包含该书的图书馆后立即返回 true,您的原始解决方案可能会更有效。

    def has_book?(book)
      libraries.each do |l|
        return true if l.books.include?(book)
      end
      return false
    end
    

    顺便说一句。 php 和 ruby​​ 几乎同时出现。

    【讨论】:

    • 你的第一个 sn-p 根本不需要map:你可以只使用collection.any? { |element| element.whatever? } 这和后者一样有效,因为它在遇到第一个true 时会中断。
    • 好点。谢谢你纠正我。那么any? 加块是解决这个问题的最好方法。
    【解决方案3】:

    这看起来是最缩小的版本,我看不到任何进一步缩小它的方法:

    def has_book?(a)c=false;libraries.each{|b|c=true if b.books.include?a};c end
    

    【讨论】:

      【解决方案4】:

      我不知道为什么@Зелёный 删除了他的答案,但这是一个很好的 IMO,所以我把它贴在这里:

      def has_book?(book)
        libraries.includes(:books)
                 .where(books: {id: book.id})
                 .any?
      end
      

      【讨论】:

      • 旁注:我个人尽量避免在where 中使用嵌套散列,因为它们依赖于表名。另一种方法是使用merge,如下所示:.merge(Book.where(id: book.id))。此更改按原样没有意义,但允许您将内部 where-clause 交换为 Book 类的范围。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-16
      • 2018-04-18
      相关资源
      最近更新 更多