簡體   English   中英

如何重構一個大型的Ruby類?

[英]How to refactor a large Ruby class?

我有一個足夠大的控制器類,這是一種不好的做法(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

通過對您的問題的討論,我的想法是確定正在計算重定向路徑的各種私有方法是否可以屬於特殊目的的類,該類抽象了路徑計算邏輯的各個方面,或者可能僅僅是控制器混合使用的模塊正確的答案將在很大程度上取決於您的邏輯在各種私有方法中的模樣。 一個簡單的模塊不太可能是正確的方法,因為您只是將代碼移到其他地方以滿足任意度量標准。 確定所有私有方法的原因並提出更好的抽象可能是正確的方法,但是可能會發揮不同的作用。

本文討論的許多相同模式都將適用於超重控制器和模型: 重構Fat ActiveRecord模型的7種模式

因此,從評論中提取結論,我喜歡這兩個想法:

  • 常識。 只有作為開發人員的您才能知道代碼的結構,因此工具只能提出建議,但是您有最終決定權。 可以通過代碼中的注釋配置Rubocop以禁用某些檢查。
  • 在重構的情況下,可以將控制器中的私有方法提取到幫助程序中。

我同意,最后的話將永遠來自開發人員,但是如果您添加諸如rubocop之類的工具是為了鼓勵您編寫更好的代碼,那么對我來說,添加rubocop然后禁用一些檢查是沒有意義的。
我也不會使用輔助方法,原因是一類應該只承擔一種責任,所以它應該只具有一種行為。 人們傾向於將各種類型的方法放入助手中,這些方法具有完全不同的行為,從而賦予該類許多不同的責任。 如果它的所有方法只有一個目的,那么我只會使用一個助手。
在您的特定情況下,我會更傾向於將知識提取到簡單的類中。 嘗試識別不同的行為並將其封裝到類中。
在這種情況下,您似乎擁有某種url構建器,因此可行的解決方案可能是:

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 helper方法,否則您將必須制作自己的url構建器。 如果有人有其他想法,請與我們分享。
  • 如果發現有不止一種行為,那么我將分成多個類,與您發現的行為一樣多。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM