Плюсы и минусы использования фабрики против обычного конструктора

(Использование Python 3.2, хотя я сомневаюсь, что это имеет значение.)

я имею class Data, class Rulesи класс Result, Я использую строчные буквы для обозначения экземпляра класса.

rules объект содержит правила, которые, если применяются к data объект, может создать result объект.

Я решаю, куда поместить (довольно сложный и развивающийся) код, который на самом деле применяет правила к данным. Я вижу два варианта:

  1. Поместите этот код в класс Result метод, скажем parse_rules, Result конструктор будет принимать в качестве аргумента rules объект и передать его на self.parse_rules,

  2. Поместите этот код в новый класс ResultFactory, ResultFactory будет одноэлементный класс, который имеет метод, скажем, build_result, который занимает rules в качестве аргумента и возвращает вновь построенный result объект.

Каковы плюсы и минусы двух подходов?

5 ответов

Решение

Принципы проектирования GRASP содержат рекомендации по распределению ответственности между классами и объектами в объектно-ориентированном проектировании. Например, шаблон Creator предлагает: В общем, класс B должен отвечать за создание экземпляров класса A, если применяется одно или, предпочтительно, несколько из следующего:

  • Экземпляры B содержат или составно агрегируют экземпляры A
  • Экземпляры B записывают экземпляры A
  • Экземпляры B тесно используют экземпляры A
  • Экземпляры B имеют начальную информацию для экземпляров A и передают ее при создании.

В вашем примере у вас есть сложный и развивающийся код для применения правил к данным. Это предполагает использование фабричного шаблона.

Помещение кода в Results противопоказано, потому что 1) результаты не создают результатов, и 2) результаты не являются экспертом по информации (то есть они не обладают большей частью необходимых знаний).

Короче говоря, ResultFactory кажется разумным местом для концентрации знаний о том, как применять правила к данным для получения результатов. Если бы вы попытались внедрить всю эту логику в конструкторы классов для Результатов или Правил, это привело бы к тесной связи и потере сцепления.

Третий сценарий:

Вы можете рассмотреть третий сценарий:

  • Поместите код в метод Rules.__call__,
    Инстанцирование Result лайк: result = rules(data)

Плюсы:

  • Resultмогут совершенно не знать о Rules что генерирует их (и, возможно, даже оригинал Data).
  • каждый Rules подкласс может настроить его Result создание.
  • Это естественно (для меня) Rules применительно к Data Уступать Result,
  • И у вас будет пара принципов GRASP на вашей стороне:
    • Создатель: экземпляры Rules иметь инициализирующую информацию для экземпляров Result и передать его на создание.
    • Информационный эксперт: Информационный эксперт приведет к возложению ответственности на класс с наибольшим количеством информации, необходимой для его выполнения.

Побочные эффекты:

  • Муфта: Вы поднимите муфту между Rules а также Data:
    • Вам нужно передать весь набор данных каждому Rules
    • Это означает, что каждый Rules должен быть в состоянии решить, к каким данным он будет применяться.

Можете ли вы сделать ResultFactory чистой функцией? Бесполезно создавать одноэлементный объект, если все, что вам нужно, это функция.

Почему бы не поставить правила в своих классах? Если вы создаете класс RuleBase, то каждое правило может быть его производным. Таким образом, полиморфизм может быть использован, когда Data требует применения правил. Данные не должны знать или заботиться о том, какие экземпляры Правил были применены (если только Данные сами не знают, какие правила следует применять).

Когда необходимо вызвать правила, экземпляр данных может все RuleBase.ExecuteRules() и передать себя в качестве аргумента. Правильный подкласс Rule может быть выбран непосредственно из Data, если Data знает, какое правило необходимо. Или можно использовать другой шаблон проектирования, например, Chain of Responsibility, где Data вызывает шаблон и позволяет возвращать результат.

Это сделало бы отличное обсуждение доски.

Ну, второе совершенно глупо, особенно со всей единственностью. Если Result требует Rules чтобы создать экземпляр, и вы не можете создать его без него, он должен принять это в качестве аргумента __init__, Нет необходимости делать покупки.

Другие вопросы по тегам