2014-11-05 65 views
0

我的最佳方式之间徘徊,以实现此服务:依赖注入的正确实施

目前我有这样的:

class ReissueInvoices 

    def initialize(registration, invoice_gateway, invoice_generator) 
    @registration = registration 
    @invoice_gateway = invoice_gateway 
    @invoice_generator = invoice_generator 
    end 

    def call 
    void_current_invoices 
    regenerate_invoices 
    create_third_party_invoices 
    end 

    private 

    attr_reader :registration, :invoice_gateway, :invoice_generator 

    def void_current_invoices 
    registration.invoices.each do |invoice| 
     unless invoice.paid? 
     invoice_gateway.void_invoice(invoice) 
     end 
    end 
    end 

    def regenerate_invoices 
    invoice_generator.call(registration) 
    end 

    def create_third_party_invoices 
    invoice_gateway.create_invoices(registration) 
    end 

end 

,我把这个(通常是从我的控制器)是这样的:

ReissueInvoices.new(@registration, InvoiceGateway.new, InvoiceGenerator.new).call 

我明显有一个InvoiceGateway,InvoiceRegistration类,并将它们作为依赖项传递给我的ReissueInvoices类。

这是做事情的最佳方式吗?这是否正确实施了依赖注入?或者我应该改变我的ReissueInvoices类像这样的初始化方法去除参数和添加私有方法来创建和访问invoice_generator和invoice_gateway对象:

class ReissueInvoices 

    def initialize(registration) 
    @registration = registration 
    end 

    def call 
    void_current_invoices 
    regenerate_invoices 
    create_third_party_invoices 
    end 

    private 

    attr_reader :registration 

    def invoice_gateway 
    @invoice_gateway ||= InvoiceGateway.new 
    end 

    def invoice_generator 
    @invoice_generator ||= InvoiceGenerator.new 
    end 

..... 

,并调用它像这样

ReissueInvoices.new(@registration).call 

最后,你们怎么想的初始化定义这样的默认参数的:

def initialize(registration, invoice_gateway=InvoiceGateway.new, invoice_generator=InvoiceGenerator.new) 
    @registration = registration 
    @invoice_gateway = invoice_gateway 
    @invoice_generator = invoice_generator 
end 

是好是坏?

感谢,

马特

回答

1

为什么你的网关不需要像凭据?我猜它是的,网关的凭证只是硬编码。真的,应该在某个地方进行初始化,然后传入(因为你的类应该不需要处理如何设置网关,大概只有一个网关,并且你应该到处使用同一个对象)。

我不会打扰传递发票生成器,除非它很昂贵,或者您需要控制它返回的测试或有多种方式来生成该事件,并且您无法从这里合理地知道哪些是正确的。这只是因为它是一个计算并返回一个值的东西。不错,简单,除了我提到的那些之外。

而且,我可能会改变它是这样的:

module ReissueInvoices 
    def self.call(registration, invoice_gateway) 
    registration.invoices.each do |invoice| 
     invoice_gateway.void_invoice(invoice) unless invoice.paid? 
    end 
    InvoiceGenerator.call(registration) 
    invoice_gateway.create_invoices(registration) 
    end 
end 

的思维过程就大约是这样的:

  • 我永远不会看那个调用方法而不需要看他们实施的方法,所以让我们看看他们做了什么。哦,他们只是隐藏了合作者。
  • 拉起来到#call
  • “为什么我实例化一个InvoiceGenerator?它不带任何参数,所以它不应该具有的状态,所以无需实例。我认为它只有一个方法,因为该方法被命名为#call,所以只要将它设置为单例方法,并且如果有一些实例化的价值,那么单例方法可以做出这个决定。
  • 现在一切都在ReissueInvoices#call中,剩下的是什么?这只是布线以支持此行为的对象(#initialize和访问器)。相反,使它成为名为call的类方法。然后,这些变成了局部变量。
  • 既然我们只有一个类的方法,使得这个类是误导性的,因为它不会被实例化。所以把它变成一个模块吧。