Шаблон стратегии для моделей выставления счетов, которые используют разные данные для расчета? - PullRequest
3 голосов
/ 03 декабря 2009

У нас есть модель счета-фактуры, которая выставляет счет клиентам несколькими различными способами. Для краткости я собираюсь сосредоточиться на двух: цена за показ и цена за телефонный запрос. Моя мысль заключалась в том, чтобы реализовать эти (и остальные) как стратегии, а затем динамически смешивать их в классе счетов.

Это представляется целесообразным, поскольку для определения количества показов / вызовов используются разные источники информации. Это может быть включено в стратегию при сохранении базовой формулы в классе Invoice.

Расчет цены за показ прост: num impressions X cost per impression.

Расчет телефонных запросов немного сложнее: 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

Тогда модули могут быть:

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 секунд, мне нужно написать новую стратегию. Какой лучший дизайн для решения этой проблемы?

Ответы [ 2 ]

3 голосов
/ 04 декабря 2009

Не реализуйте свои стратегии как модульные миксины. Реализуйте их как полноценные классы с помощью открытого метода PerInquiryCalculation и внедрите нужный класс в класс Invoice, используя его конструктор.

Таким образом, каждый класс стратегии может иметь свои собственные переменные состояния, установленные во время построения. Конструктор PerInquiryStrategy может принимать порог длительности, который метод PerInquiryCalculation использует для расчета сборов.

0 голосов
/ 03 декабря 2009

Вы можете получить все смешанные модули и базовый класс, используя метод класса ancestors. Так что если у вас есть экземпляр myInvoice, вы можете просто использовать myInvoice.class.ancestors. Он возвращает массив констант, так что вы можете проверить на включение.

Кстати, в этом контексте я думаю, что традиционная композиция / агрегация более уместна в этом случае: безопаснее, когда несколько различных стратегий сосуществуют одновременно. Вы не хотите, чтобы закончилось изменение стратегии всех счетов, потому что вы затронули базовый класс ...

...