GRASP — это не шаблоны в готовом к применению виде, как GoF, а набор руководящих принципов для принятия проектных решений. Они формируют ментальную модель для распределения обязанностей в системе.
- Информационный эксперт (Information Expert). Самый фундаментальный принцип. Ответственность должна быть назначена тому классу, который обладает всей необходимой информацией для ее выполнения. Пример: в системе заказов класс `Order` знает свои позиции (`OrderItems`). Кто должен рассчитывать общую сумму заказа? Класс `Order`, так как у него есть доступ ко всем необходимым данным. Это интуитивно и снижает связность.
- Создатель (Creator). Класс B должен создавать экземпляры класса A, если выполняется одно из условий: B содержит A, B агрегирует A, B владеет инициализирующими данными для A, B активно использует A. Пример: класс `Order` создает экземпляры `OrderItem`, так как он их агрегирует. Это естественно и инкапсулирует логику создания.
- Контроллер (Controller). Первый приемник входящих системных операций (запросов пользователя) не должен быть UI-объектом (кнопкой, формой). Эту роль должен выполнять объект-посредник, представляющий либо всю систему (системный контроллер), либо сценарий использования (use-case контроллер). В паттерне MVC это контроллер. Он координирует работу между представлением и доменной моделью, но не должен содержать бизнес-логику.
- Слабая связность (Low Coupling). Этот принцип оценивает качество распределения ответственности. Выбирайте такое распределение, которое приводит к слабой зависимости между классами (низкой связности). Это повышает возможность повторного использования и упрощает поддержку. GRASP предлагает использовать его как критерий для выбора между альтернативными назначениями ответственности.
- Высокое зацепление (High Cohesion). Тесно связан с предыдущим. Ответственности класса должны быть тесно связаны между собой и фокусироваться на одной цели. Высокое зацепление делает классы более понятными, управляемыми и снижает вероятность изменений по разным причинам.
- Полиморфизм (Polymorphism). Если поведение варьируется в зависимости от типа, используйте полиморфизм для назначения ответственности за это поведение классам-потомкам, а не условные операторы в базовом классе. Это прямой путь к применению паттернов Стратегия, Состояние, Команда. Пример: расчет скидки. Вместо `if (customer.isVIP())` создайте иерархию `DiscountStrategy` с реализациями `VipDiscount`, `RegularDiscount`.
- Чистая выдумка (Pure Fabrication). Класс, не представляющий понятие из предметной области, созданный исключительно для достижения низкой связности, высокого зацепления и возможности повторного использования. Классический пример — репозиторий или фасад. `OrderRepository` — это «выдумка», его нет в бизнес-требованиях, но он берет на себя ответственность за доступ к данным, освобождая доменный класс `Order`.
- Посредник (Indirection). Назначьте ответственность за взаимодействие между двумя компонентами промежуточному объекту-посреднику, чтобы обеспечить слабую связность между ними. Это суть многих паттернов: Посредник (Mediator), Адаптер, Фасад, Наблюдатель. Например, шина событий (Event Bus) является посредником между отправителями и получателями событий.
- Устойчивость к изменениям (Protected Variations). Выявите точки потенциальной изменчивости или нестабильности в системе и изолируйте их, назначив ответственность за создание стабильного интерфейса вокруг них. Это принцип проектирования «навынос». Все паттерны, по сути, служат этой цели. Пример: использование интерфейса `PaymentGateway` для защиты системы от изменений в конкретных провайдерах (Stripe, PayPal).
* **Уровень абстракции:** GRASP находится на более высоком, концептуальном уровне. Он отвечает на вопрос «что кому поручить?». SOLID — это принципы уровня модулей и классов, которые дают более конкретные технические указания («зависи от абстракций», «класс должен иметь одну причину для изменений»). Паттерны GoF — это готовые, типовые решения часто встречающихся проблем низкого и среднего уровня.
* **Взаимосвязь:** Принципы GRASP часто являются причиной, а SOLID и паттерны — следствием или средством реализации. Например, стремление к **Слабой связности (GRASP)** приводит к следованию **Принципу инверсии зависимостей (D из SOLID)**. Применение **Полиморфизма (GRASP)** для **Устойчивости к изменениям (GRASP)** реализуется через паттерн **Стратегия (GoF)** и соответствует **Принципу открытости/закрытости (O из SOLID)**.
* **Фокус:** GRASP фокусируется на ответственностях и структуре взаимодействий. SOLID фокусируется на архитектуре зависимостей и стабильности дизайна. Паттерны фокусируются на решении конкретных проблем взаимодействия объектов.
Вывод: GRASP — это недостающее звено между анализом требований и детальным проектированием. Это язык для обсуждения и обоснования архитектурных решений в команде. SOLID и паттерны — это инструменты для реализации решений, принятых на основе GRASP. Понимание GRASP позволяет осознанно применять SOLID и выбирать паттерны, создавая не просто рабочее, но и элегантное, гибкое и поддерживаемое программное обеспечение. Освоив GRASP, вы переходите от кодирования к настоящему проектированию.
Комментарии (9)