Немного разные результирующие данные при фильтрации за месяц или за все время. Какие шаблоны проектирования применяются?

#php #oop #symfony #design-patterns

#php #ооп #symfony #шаблоны проектирования

Вопрос:

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

Когда я выбираю «Все время», я хотел бы показать все те же ключевые показатели эффективности, кроме одного. Улучшение по сравнению с прошлым месяцем будет средним за все время для каждого пользователя.

Какой шаблон проектирования я использую для реализации этой функциональности? Поскольку оба вызова API для моего серверной части Symfony2, вероятно, будут использовать одну и ту же конечную точку, только с другим параметром МЕСЯЦ против всего времени (или, возможно, с другой конечной точкой). И они на 90% будут выполнять те же вычисления, я бы хотел сделать это как можно более общим, чтобы разрешить, возможно, другие параметры в будущем.

Должен ли я создать стратегию, подобную MonthFilterStrategy и AllTimeFilterStrategy, и установить контекст на основе параметра или есть лучший шаблон проектирования, который применим к этому варианту использования.

Ответ №1:

  1. Создайте отдельные методы / конечные точки в своих контроллерах и на бизнес-уровне
  2. Если эти методы используют какой-то код, переместите его в еще один непубличный метод

URL-адреса:

 http://my-domain.com/get-results/2014/06
http://my-domain.com/get-results/all-time
  

Контроллеры / действия:

 public function getResultsByMonthAction($year, $month) {
    $from = DateTime::createFromFormat('Y-m-d', sprintf('%d-%d-01', $year, $month));
    $from->setTime(0, 0, 0);
    $to = $from->modify('next month');

    $results = $this->myService->getResultsByDateRange($from, $to);

    return $this->handleCommonCode($results);
}

public function getAllTimeResultsAction() {
    $results = $this->myService->getAllTimeResults();

    return $this->handleCommonCode($results);
}

private function handleCommonCode($results) {
    ...

    $abc = $this->processResultsSomehow($results);

    return $this->renderTemplate('...', [
        'someExtraData' => $abc,
        'results' => $results
    ]);
}
  

Обслуживание:

 public function getResultsByDateRange(DateTime $from, DateTime $to) {
    if ($from > $to) {
        throw new LogicException('Invalid range. $from must be lower than $to.');
    }

    $criteria = [
        'date-rage' => [$from, $to]
    ];

    return $this->getResults($criteria);
}

public function getAllTimeResults() {
    return $this->getResults();
}

protected function getResults(array $criteria = []) {
    // let's assume you're quering database (using Doctrine)
    $queryBuilder = ...;

    if (isset($criteria['date-rage'])) {
         $queryBuilder
             ->andWhere('abc.someDate BETWEEN :dateRangeStart AND :dateRangeEnd')
             ->addParameters([
                  'dateRangeStart' => $criteria['date-rage'][0],
                  'dateRangeEnd'   => $criteria['date-rage'][1]
             ]);
    }

    return $queryBuilder->getQuery()->getResult();
}
  

Этот подход требует немного больше кода, но он имеет свои преимущества:

  1. Гораздо проще документировать и понимать API,
  2. Нет необходимости в бесчисленных if заявлениях,
  3. Проще расширять / переопределять, поскольку каждая часть кода находится в отдельном методе,
  4. Упрощение отладки и обслуживания,
  5. Каждый метод может содержать некоторую индивидуальную логику,
  6. Поддержка сторонних инструментов (IDE, анализаторы кода и т.д.)

Ответ №2:

Я бы предположил, что если нет параметров, с помощью которых можно охватить дату, вы бы применили свои вычисления через N месяцев, где N — некоторый разумный предел (или нет; YMMV). Учитывая это, обработка должна выполняться для данных за N месяцев и никогда не предполагать, что для обработки может быть только один объект. Всегда предполагайте, что вы будете обрабатывать данные за N месяцев, а затем позволять наличию параметров области видимости / фильтрации управлять пользовательским интерфейсом.