views:

94

answers:

2

we have an invoice model that bills clients in a few different ways. for brevity sake, i'm going to focus on two: cost per impression and cost per phone inquiry. my thought was to implement these (and the rest) as strategies and then dynamically mix them in to the invoice class.

this seems appropriate because there are different sources of information used to determine the number of impressions/calls. this could be encapsulated in the strategy, while keeping the basic formula in the Invoice class.

the caluclation for cost per impression is simple: num impressions X cost per impression

the calculation for phone inquiries is a little more complicated: num calls X cost per call

class Invoice
  def self.strategy
    self.class_eval <<-EOS
    include #{billing_type}
    EOS
  end

  def invoice_amount
    # this will used the module mixed in above
    self.rate * calculate_impressions
  end
end

then the modules could be

module PerImpressionCalculation
  def calculate_impressions
     # get the number of impessions from source a...
  end
end

module PerInquiryCalcuation
  def calculate_impressions
     # get the number of impessions from source b...
  end
end

however, whether a call counts or not is based on the length of the call and this varies from model to model. thus, when i'm searching through the phone logs i need to have this value.

my question is where does this value get stored? i could create a strategy for invoices that are based on 10 second calls and a separate one for 30 second ones, but that seems wasteful. if a deal came in that wants the threshold to be 15 seconds, i need to write a new strategy.

insight?

thanks, hubert

A: 

You can retrieve all mixed modules and base class using the class method ancestors. So if you have an instance myInvoice, you can simply use myInvoice.class.ancestors. It returns an array of constants so you can check for inclusion.

BTW, in this context, I think that traditional composition/aggregation is more appropriate in this case: it is safer when several different strategy coexists at the same time. You do not want ending in changing all invoices strategy because you affected the base class...

paradigmatic
+1  A: 

Don't implement your strategies as module mixins. Implement them as full fledged classes with a public PerInquiryCalculation method and inject the right one into the Invoice class using its constructor.

This way each strategy class can have its own state variables set during construction. The constructor of PerInquiryStrategy can take a duration threshold that the PerInquiryCalculation method uses to calculate the fees.

Ryan Michela