GRASP — General Responsibility Assignment Software Patterns — это набор из девяти принципов, введённых Крейгом Ларманом в книге «Применение UML и паттернов» (1997). Там, где SOLID описывает структуру отдельных взаимоотношений классов, GRASP отвечает на более фундаментальный вопрос, с которым сталкивается каждый разработчик при проектировании: какой объект должен отвечать за это поведение? GRASP предоставляет именованные эвристики для систематического ответа на этот вопрос, а не интуитивного. Паттерны — это не алгоритмы, а линзы, делающие процесс рассуждения явным и коммуникабельным.
Информационный эксперт — наиболее часто применяемый паттерн GRASP и источник самого распространённого вопроса проектирования: «Куда поместить этот метод?» Ответ: в класс, обладающий данными, которые нужны методу. Если расчёт итога заказа требует знания строк заказа, класс Order (содержащий строки) должен вычислять свой собственный итог — а не внешний сервис, залезающий внутрь Order за строками.
Паттерн Контроллер отвечает на вопрос: кто должен обрабатывать системное событие (действие пользователя, входящее сообщение, плановый триггер)? Не доменные объекты — они должны не знать о механизмах доставки. Не UI — он должен не знать о бизнес-логике. Контроллер — это не-UI класс, который получает события и делегирует доменным объектам. Он координирует, но не вычисляет. На практике: REST-контроллер — это Контроллер по GRASP. Как и потребитель очереди, обработчик команды CLI или планировщик пакетного задания — все они контроллеры для разных механизмов доставки.
Паттерн Полиморфизм адресует поведенческую вариативность, зависящую от типа. Когда вы видите switch или if/else по полю типа — это обычно сигнал применить паттерн: каждая ветка условного оператора должна стать подтипом, а поведение должно диспетчеризоваться системой типов, а не вызывающим кодом. Это прямая связь с OCP: switch растёт с каждым новым типом; полиморфизм означает добавление нового типа без изменения существующего кода.
Ларман назвал Устойчивость к изменениям «наиболее фундаментальным принципом в разработке ПО» — и сложно с этим поспорить. Каждый паттерн проектирования, каждый архитектурный стиль, каждая абстракция существуют для того, чтобы защитить стабильный код от нестабильных изменений. Практическое применение: выявляйте точки нестабильности вашей системы (внешние API, часто меняющиеся бизнес-правила, технология базы данных, сторонние библиотеки) и оборачивайте каждую стабильным интерфейсом. Код, зависящий от интерфейса, защищён — он не изменится при изменении нестабильного за ним.
Искусственная сущность разрешает противоречие между высокой связностью и необходимостью где-то разместить инфраструктурные задачи. Рассмотрим персистентность: сущность Order не должна знать, как сохранить себя в базу данных — это нарушило бы SRP и внесло инфраструктуру в домен. Но логика персистентности должна где-то жить. Repository — искусственная сущность: класс, изобретённый ради проектирования, не имеющий прямого аналога в предметной области. Он существует для того, чтобы дать поведению персистентности высокосвязный, слабосвязанный дом. Другие примеры: Mapper, Logger, EventPublisher, CacheManager — все они искусственные сущности.