Русский
Русский
English
Статистика
Реклама

SOLID на практике. Принцип открытости-закрытости иActiveQueryYii2

Как-то в рабочей беседе один мой коллега-программист заметил, что всевозможные принципы и паттерны проектирования ПО хорошо применять, когда делаешь тестовые задания, однако в реальных, боевых проектах они как правило неприменимы. Почему так? Основных причин две:

  • Реализация принципов и паттернов требует слишком много времени.

  • Код становится тяжеловесным и сложным для понимания.

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

Отправная точка

Работаем над проектом на Yii2, в котором для доступа к данным используетсяActiveRecord. Клиентский код загружает некий набор данных, используя методActiveRecord::find().

classClientClass{  // Много кода... publicfunctionbuildQuery():ActiveQueryImplementation { $query=ActiveRecordModel::find(); // Получаем экземплярActiveQueryиз модели $query->active()->unfinished(); // Применяем условия, реализованные в конкретном классеActiveQuery   return$query; // Далее результаты построенияActiveQueryиспользуются для получения выборки из БД, например $query->all(); }  // Много кода...}

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

А если нужно добавить новые условия в запрос?

Придерживаясь традиционного подхода, мы добавим вызовы методов с новыми условиями прямо в строку, применяющую эти условия к запросу.

$query->active()->unfinished()->newConditionA()->newConditionB();

Вуаля! Пять секунд работы, и мы получили изящный, легко читаемый код.

Но что если эти условия нужны не во всех случаях, когда вызывается наш метод? Что если условия к запросу нужно применять динамически?

Тут нас ждут определенные трудности. Очевидно, что при таком подходе весь клиентский код, использующий наш метод, будет получать запрос, к которому уже применены новые условия. Почему так получилось? Потому что мы...

Нарушаем принцип открытости-закрытости

Напомню, что принцип открытости-закрытости SOLID гласит:

Код должен быть открытым для дополнения и закрытым для изменения.

Мыизмениликод нашего метода таким образом, что он начал выдаватьдругиерезультаты.

А как сделать правильно?

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

Для этого изменим код нашего метода следующим образом.

classClientClass{  /**  * @varActiveQueryFilter[]  */ public$filters= []; // Добавляем возможность сконфигурировать экземпляр класса массивомфильтров  // Много кода... publicfunctionbuildQuery():ActiveQueryImplementation { $query=ActiveRecordModel::find(); $query->active()->unfinished();   $this->applyFilters($query);// Применяем фильтры к запросуreturn$query; } privatefunctionapplyFilters(ActiveQueryImplementation&$query):void  {   foreach($this->filtersas$filter){     $filter->applyTo($query);    }  }  // Много кода...}

Определим интерфейсActiveQueryFitlerпредполагает единственный метод applyTo(), применяющий дополнительные условия к запросу в качестве побочного эффекта.

interfaceActiveQueryFilter{ publicfunctionapplyTo(ActiveQuery$query):void;}

Теперь для добавления в запрос новых условий нам достаточно добавить соответствующую реализацию интерфейсаActiveQueryFilter.

classNewConditionsAAndBFilterimplementsActiveQueryFilter{ publicfunctionapplyTo(ActiveQuery$query):void  {    $query->newCondtionA()->newConditionB();  }}

Что мы имеем в итоге

  • Мы решили стоящую перед нами задачу,дополнивпервоначальный метод всего одним вызовом (минимальное вмешательство в первоначальный код).

  • Поведение по умолчанию исходного метода не изменилось.

  • Вызываемый из исходного метода новый методapplyFilters() не реализовывает собственной логики вся логика делегируется классам фильтров. Таким образом, мы оставили неизменным и поведение всего исходного класса.

Источник: habr.com
К списку статей
Опубликовано: 03.12.2020 16:09:25
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Php

Проектирование и рефакторинг

Yii

Solid

Принцип открытости-закрытости

Yii2

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru