如何重构一个大的Ruby类?

时间:2014-07-04 21:14:51

标签: ruby-on-rails ruby ruby-on-rails-4

我有一个足够大的控制器类,这是一个不好的做法(Rubocop抛出这个警告:类定义太长)。

该类有许多私有方法,它们都计算重定向到的路径,因此它是一个控制器问题。

怎么可能被重构?

示例代码:

class PostController
  def new
    @post = Post.new
  end

  def create
    @post = Post.new(post_params)
    # ...
  end

  # more resources methods

  private

  def post_params
    # ...
  end

  def post_url(post)
    if params['submit-save'] || params['submit-publish']
      url_for [:edit, post]
    else
      url_for [:review, post]
    end
  end

  def next_post_url(post)
    next_post = post.find_next

    if next_post
      url_for [:edit, post]
    else
      some_path(next_post)
    end
  end

  # some more methods
end

3 个答案:

答案 0 :(得分:0)

从你对问题的讨论中,我的想法是确定计算重定向路径的各种私有方法是否属于一个特殊目的类,它抽象了路径计算逻辑的各个方面,或者可能只是一个模块,控制器混入。正确的答案将在很大程度上取决于您在各种私有方法中的逻辑。一个简单的模块不太可能是正确的方法,因为您只是将代码移动到其他地方以满足任意度量标准。确定所有私有方法的原因并提出更好的抽象可能是正确的方法,但可能会有不同的模式发挥作用。

本文中讨论的许多相同模式将适用于超重控制器和模型:7 Patterns to Refactor Fat ActiveRecord Models

答案 1 :(得分:0)

因此,从评论中得出结论,我喜欢这两个想法:

  • 常识。只有你作为开发人员知道如何构建代码,所以工具只能建议,但你有最后的决定权。可以通过代码中的注释配置Rubocop以禁用某些检查。
  • 如果是重构,控制器中的私有方法可以被提取到帮助器中。

答案 2 :(得分:0)

我同意最后一句话总是来自开发人员,但是如果你添加像rubocop这样的工具是为了鼓励你编写一个更好的代码,那么添加rubocop然后禁用一些检查是没有意义的。
我也不会使用帮助方法,背后的原因是一个类应该只有一个责任,所以它应该只有一个行为。人们倾向于将所有类型的方法放在帮助者中,具有完全不同行为的方法赋予该类许多不同的职责。如果它的所有方法只有一个且只有一个目的,我会使用帮助器 在您的特定情况下,我会更倾向于将知识提取到普通类中。尝试识别不同的行为并将其封装到类中 在这种情况下,看起来你有一些网址构建器,所以一个可行的解决方案可能是这样的:

class PostController
  def new
    @post = Post.new
  end

  def create
    @post = Post.new(url_builder.post_url)
    # ...
  end

  # more resources methods

  private

  def url_builder
    UrlBuilder.new(self, params)
  end
end

class UrlBuilder
  def initialize(self, params)
    @self = self
    @params = params
  end

  def post_url(post)
    if params['submit-save'] || params['submit-publish']
      self.url_for [:edit, post]
    else
      self.url_for [:review, post]
    end
  end

  def next_post_url(post)
    next_post = post.find_next

    if next_post
      self.url_for [:edit, post]
    else
      some_path(next_post)
    end
  end
  private
  attr_reader :self, :params
end  

这不是一个完全可行的例子,因为我不知道你的控制器的整个实现,只是一个需要一些调整的可行解决方案。关于该解决方案的几点要说的是:

  • 我会将课程移到一个完全不同的文件中。
  • 我不喜欢在物体之间传递自我的想法,我认为这不是一件好事 想要将对象的上下文传递给另一个对象,它会创建 两者之间的耦合是因为人们需要知道的 另一个背景,但在这种特殊情况下,我是唯一的方法 看,如果你想使用的url_for辅助方法 控制器,否则你将不得不制作自己的网址构建器。如果 任何人有其他想法请与我们分享。
  • 如果你发现不仅仅有一种行为,那么我 然后会分裂成多个类,就像你找到的行为一样多。