2013-02-08 46 views
1

比方说,我有一个帐户类和一个AccountReport类。在帐户#显示我想显示一个帐户的报告。 Account和AccountReport都有一些公开的方法。以下哪种技术更好?委托或实例化额外的类?

1)实例化一个账户和一个账户报告,用账户数据初始化账户报告。

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

    respond_with(@account) 
    end 

    # ... 
end 

2)允许帐户的实例来实例化AccountReport和委托方法调用

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 

选项2似乎是一个更简洁的方法给我,但有很多的方法加载了帐户使得它感觉像一个上帝阶级。

回答

2

嗯,我认为你必须使这两种选择的组合。

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

随着第二个,您的报告将实例化,它可能会降低性能。

你或许应该尝试这样的事:

class Account < ActiveRecord::Base 
    # ... 

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

    # ... 
end 

这种解决方案的好处是,如果需要的报告只装,但不会每次加载。 这个解决方案的坏处是如果你添加一些订单你的报告将不会是最新的。

UPDATE: 为了改善这一点,你可以用这一个

if @report.nil || self.created_at_changed? 
+0

我想我明白了。我喜欢懒惰地加载报告的想法。是否有可能以这种方式委托给AccountReport/Report,或者是否需要使用方法链接account.report.total,并使用此方法? –

+0

'@report || = AccountReport.new(self.orders)'是你上面试图做的一个很好的比喻。 –

+0

谢谢!我已经将这两条建议结合起来,它的运作非常好。我甩掉了我的读者,写了一个获取报告的方法,然后在那里返回或初始化它。 –

0

我喜欢的第一个选项,因为它使低耦合更换条件。第二个选项以一种可能不必要的方式将Account和AccountReport关联在一起。每当你得到另一种类型的报告时会发生什么?您可能需要更改帐户中的一些内容,这很令人伤心,因为它们看似不相关。

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

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

然后,要使用它的控制器:

AccountReporting.new(current_user.account) 

这是否有道理?

+0

有趣。我可以看到这会有用。我认为对于经常使用的类,我可以使用方法#2的精炼版本,对于不常用的类,我可以使用这种方法(改进#1)。您预先准备好了几种这样的类,这是正确的。我试图削减我的应用程序的两个上帝类更好的SRP /解耦。 –