【问题标题】:Should I use class method or instance method, and why?我应该使用类方法还是实例方法,为什么?
【发布时间】:2012-07-24 05:32:12
【问题描述】:

在我的 Rails 应用程序中,创建业务时,我有一个包含以下字段的表单:

   <%= check_box_tag(:default_company) %> 
   <%= label_tag(:default_company, "Set Company as Default") %>

基本上当我创建业务时,如果他们选中此框,我需要它运行类似于以下代码的内容:

def set_default_company(company, user)
  exists = DefaultCompany.find(user.id)
  if exists
    exists.update_attributes(company: company)
  else  
    DefaultCompany.create(company: company, user: user)
  end
end

在学习时,我通常会在我的控制器中做这些事情,但我正在尝试遵循最佳实践并使用胖模型、瘦控制器,所以我想使用这样的逻辑:

def create
  @company = Company.new(params[:company])

  if @company.save
    if params[:default_company]
      Company.set_default_company(@company.id, current_user.id,)
    end
    flash[:notice] = "Company was successfully created."
    redirect_to @company
  else
    redirect_to new_company_path
  end
end

这是我对使用类方法还是实例方法调用set_default_company 感到困惑的地方。他们似乎都可以工作,但我看不出其中一个有什么好处。

除了向我提供有关使用哪种方法的任何信息外,如果有人可以向我展示将其作为类方法与实例方法编写的简要实现,它可能会让我更好地理解原因。

我会这样写:

def self.set_default_company(company, user)
  # Logic here
end

def set_default_company(company, user)
  # Logic here
end

以这种方式写它们我也看不出有什么好处。

【问题讨论】:

    标签: ruby-on-rails ruby oop model-view-controller


    【解决方案1】:

    顾名思义,模型上的实例方法应该用于与用户的特定实例(调用该方法的实例)相关的逻辑/操作。因此您可以考虑为用户作为User 上的实例方法。类方法适用于不对模型的单个实例进行操作的事物,或者适用于您没有可用实例的情况。例如您可能有一个类方法来整理您的数据库,例如 User.purge_expired_users,它不适用于单个用户对象。

    例如

    class User
      def set_default_company(company)
        exists = DefaultCompany.find(self.id)
        if exists
          exists.update_attributes(company: company)
        else  
          DefaultCompany.create(company: company, user: self)
        end
      end
    end
    

    那么您的控制器方法将如下所示:

    def create
      @company = Company.new(params[:company])
    
      if @company.save
        if params[:default_company]
          current_user.set_default_company @company
        end
        flash[:notice] = "Company was successfully created."
        redirect_to @company
      else
        redirect_to new_company_path
      end
    end
    

    或者,您可以从另一个角度考虑关系,并在Company 上放置一个实例方法,例如company.set_as_default_for(user).

    【讨论】:

    • 对类与实例的很好描述,实际上真的为我清除了它。你是对的,我将把它转移到我的用户模型而不是公司,这最有意义并且读起来更好。我有最后一个问题。我不应该将默认公司存储在名为 Default Company 的表中,该表是 user_id 和 company_id 的连接表,我应该在用户模型中只包含一个“default_company”字段吗?我选择加入表的原因是因为并非所有用户都会有公司,事实上大多数人不会有公司,所以我会有很多空白字段。
    【解决方案2】:

    我实际上会让set_default_company 成为User 上的实例方法。一个User 有一个默认的Company;为什么Company 需要它默认的用户?

    class User
        def set_default_company(company)
            exists = DefaultCompany.find(id)
            if exists
                exists.update_attributes(company: company)
            else  
                DefaultCompany.create(company: company, user: self)
             end
         end
     end
    

    【讨论】:

    • 你是对的。我本来打算这样做,但由于某种原因,我的想法让我远离了那个。
    【解决方案3】:

    在我看来,我总是创建一个class method,如果所讨论的方法代表的信息/行为在所有实例化的对象中非常通用,不同于instance methods,我认为它更像是一个有问题的实例化对象的特定操作。

    但这是我的观点。

    【讨论】:

      【解决方案4】:

      一些事情:你有一个 DefaultCompany 的单独表吗?这似乎应该是公司表上的布尔标志。

      接下来,公司和用户之间是否存在关联?如果是这样,似乎最好的方法是

      在用户模型中

      def set_default_company(company)
        self.companies.each do |c|
          c.update_attributes(:default => false)
        end
        company.update_attributes(:default => true)
      end
      

      或者在公司模型中

      def set_as_default
        update_attributes(:default_company => true)
      end
      

      【讨论】:

      • 我确实为 DefaultCompany 提供了一个单独的表,使我远离布尔值的想法是用户通过角色拥有_many 公司,因此用户可能拥有许多公司或没有公司。所以布尔字段在这种情况下实际上不起作用,我不认为
      • 考虑公司有 5 个用户的情况,如果我将公司布尔字段设置为 true,它将为所有用户设置它,对吗?
      • 忘了说这是一个公司通过角色有很多用户,用户也通过角色有很多公司
      • 如果每个用户只能有一个默认公司,那么默认应该是角色表上的布尔值
      • 嗯是的,这是有道理的,理论上用户可以拥有“所有者”和“经理”的角色,所以在我看来,我必须同时跟踪两者?或者我想我会检查用户 a 属于公司 x 的所有角色并将所有这些角色设置为 true,这对您来说似乎比加入表更好?
      猜你喜欢
      • 2015-11-25
      • 1970-01-01
      • 2013-04-22
      • 1970-01-01
      • 1970-01-01
      • 2016-06-11
      • 2020-06-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多