使用不同数据进行计算的计费模型的策略模式?
我们有一个发票模型,可以通过几种不同的方式向客户开具账单。为了简洁起见,我将重点关注两个:每次展示成本和每次电话查询成本。我的想法是将这些(以及其余的)作为策略来实现,然后将它们动态地混合到发票类中。
这似乎是合适的,因为有不同的信息源用于确定展示次数/来电次数。这可以封装在策略中,同时将基本公式保留在 Invoice
类中。
每次展示费用的计算很简单:展示次数 X 每次展示费用
。
电话查询的计算稍微复杂一些:通话次数 X 每次通话费用
。
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
然后,模块可以是:
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
但是,呼叫是否计数取决于呼叫的长度,并且这因模型而异。因此,当我搜索电话日志时,我需要有这个值。
我的问题是这个值存储在哪里?我可以为基于 10 秒调用的发票创建一个策略,并为 30 秒调用单独创建一个策略,但这似乎很浪费。如果达成的交易希望阈值为 15 秒,我需要编写一个新策略。解决这个问题的最佳设计选择是什么?
We have an invoice model that bills clients in a few different ways. For the sake of brevity, 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 into 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 calculation 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. What is the best design choice to solve this issue?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
不要将你的策略作为模块 mixins 来实现。使用公共
PerInquiryCalculation
方法将它们实现为成熟的类,并使用其构造函数将正确的方法注入到Invoice
类中。这样每个策略类都可以在构造过程中设置自己的状态变量。
PerInquiryStrategy
的构造函数可以采用PerInquiryCalculation
方法用来计算费用的持续时间阈值。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 theInvoice
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 thePerInquiryCalculation
method uses to calculate the fees.您可以使用类方法
ancestors
检索所有混合模块和基类。因此,如果您有一个实例myInvoice
,则只需使用myInvoice.class.ancestors
即可。它返回一个常量数组,以便您可以检查是否包含。顺便说一句,在这种情况下,我认为传统的组合/聚合在这种情况下更合适:当几种不同的策略同时共存时更安全。您不希望最终更改所有发票策略,因为您影响了基类......
You can retrieve all mixed modules and base class using the class method
ancestors
. So if you have an instancemyInvoice
, you can simply usemyInvoice.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...