Comments 7
Не буду казаться умным, но такое ощущение что в данном случае паттерн используется ради паттерна. Просто реализовать функцию работы с картами и выборкой из базы гораздо быстрее чем выдумывать архитектуру там где она как будто не нужно. Но я не сеньер. Я лично стараюсь паттерны использовать только по острой необходимости. Тут каждый... как он хочет.
Пример упрощен, чтобы очистить его от лишних деталей и сосредоточиться на самом паттерне. Реальность гораздо страшнее в этой задаче.) Да, вы сами решаете, что вам применять и когда, как инженер, ответственный за задачу.)
У меня, как правило, сначала всё просто (get
, add
), потом код обрастает вот этими getByThisAndThat(…)
, а уже потом и об архитектуре приходится думать, иначе всё превратится в месиво.
Прикольно, не знал что это прям паттерн. У нас в java в Spring Data JPA (самая популярная надстройка над ORM), функциональный интерфейс, который вызывается при формировании предиката, и имеющий and, or - так и называется: Specification.
А что за первоисточник? Черная книга по паттернам корпоративных приложений Фаулера?
Пиздец, статья то про интерфейсы а тут зачем то заумное "спецификация", даже не "контракт"
Спецификация ёб ж !
Интересный подход, хотя это, пожалуй, получается не паттерн спецификации, поскольку объект, передаваемый вами в метод репозитория, содержит не логику, а дополнительные критерии.
Задачу, похожую на вашу, я на своем проекте решал несколько иным способом:
interface QueryFilter
{
/**
* Применяет условия фильтрации к переданному объекту запроса.
*/
public function applyTo(Query &$query);
}
class DoctrineLoyaltyCardRepository extends DoctrineRepository implements LoyaltyCardRepositoryInterface
{
// ...
private function findAllByFilter(QueryFilter $filter): LoyaltyCardCollection
{
// Применяем базовые параметры фильтрации
$query = $this->cardRepository->createQueryBuilder('c')
->andWhere('c.programId = :programId')
->andWhere('c.levelId = :levelId')
->andWhere('c.profileFilled = :profileFilled')
->getQuery();
// Применяем фильтр с дополнительными параметрами
$filter->applyTo($query);
$cards = $query->getResult();
return new LoyaltyCardCollection(...$cards);
}
}
Я решал проблему созданием SearchCriteria, которая сама добавляет условия в QueryBuilder.
Но на самом деле проблема разрастания репозитория решается довольно просто: достаточно в репозитории держать только common-функции, а специфичные для бизнес-логики реализовывать в сервисном слое. Никогда не понимал подхода, когда на любой чих добавляют функцию в репозиторий
Паттерн Спецификация: реальный опыт применения