1

Let's say I have an Account class and an AccountReport class. In accounts#show I want to show a report of an account. Both Account and AccountReport have a number of public methods. Which technique of the following techniques is better?

1) Instantiate an Account and an AccountReport, initializing the AccountReport with the account data.

class AccountsController < ActionController::Base
  def show
    @account = current_user.account
    @account_report = AccountReport.new(@account.orders)

    respond_with(@account)
  end

  # ...
end

2) Allow an instance of Account to instantiate AccountReport and delegate method calls

class Account < ActiveRecord::Base
  attr_reader :account_report

  delegate :method_a, :method_b, :method_c, :method_d, :to => :account_report

  after_initialize :setup_account_report

  def setup_account_report
    @account_report = AccountReport.new(orders)
  end

  # ...
end

Option 2 seems to be a cleaner approach to me but loading up Account with lots of methods makes it feel like a God class.

4

2 回答 2

2

好吧,我认为你必须混合使用这两种选择。

第一个很好,如果您只使用展示报告。第二个很好,如果您为您的帐户使用所有时间报告。

对于第二个,您的报告将一直被实例化,并且可能会降低性能。

你也许应该尝试这样的事情:

class Account < ActiveRecord::Base
  # ...

  @report = nil
  def report
    if @report.nil?
       @report = AccountReport.new(self.orders)
    end
  end

  # ...
end

该解决方案的好处是仅在需要时才加载报告,但不会每次都加载。此解决方案的坏处是,如果您添加一些订单,您的报告将不会是最新的。

更新: 为了改善这一点,您可以用这个替换条件

if @report.nil || self.created_at_changed?
于 2013-02-08T01:19:48.500 回答
0

我喜欢第一个选项,因为它保持低耦合。第二个选项以一种可能不必要的方式将 Account 和 AccountReport 联系在一起。每当您收到另一种类型的报告时会发生什么?您可能需要更改 Account 中的许多内容,这很可悲,因为它们看似无关。

您可以通过将这两个东西组合在一个服务对象中并将其交给您的视图来保持控制器中的逻辑/详细程度较低。AccountReporting服务可以处理将这两个类组合在一起的逻辑,例如:

class AccountReporting
    def initialize(account)
       @account = account
    end
    def report
       AccountReport.new(account.orders)
    end
end

然后,在控制器中使用它:

AccountReporting.new(current_user.account)

这有意义吗?

于 2013-02-08T02:12:58.350 回答