Что такое принципы GRASP в объектно-ориентированном проектировании?

«Что такое принципы GRASP в объектно-ориентированном проектировании?» — вопрос из категории ООП, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

GRASP (General Responsibility Assignment Software Patterns) — это набор из 9 принципов-паттернов, помогающих корректно распределять обязанности (responsibilities) между классами и объектами в ООП.

Основные паттерны GRASP:

  1. Информационный эксперт (Information Expert): Ответственность должна быть назначена тому классу, который обладает всей необходимой для ее выполнения информацией (данными).
  2. Создатель (Creator): Класс A должен создавать экземпляры класса B, если:
    • A содержит или агрегирует B.
    • A записывает или часто использует B.
    • A обладает данными для инициализации B.
  3. Контроллер (Controller): Не следует смешивать логику UI и приложения. Для обработки системных событий следует выделить отдельный класс-контроллер.
  4. Слабое зацепление (Low Coupling): Стремиться к минимальным зависимостям между классами для повышения гибкости и упрощения изменений.
  5. Высокое сцепление (High Cohesion): Класс должен иметь четкую, узконаправленную ответственность, а его методы должны быть тесно связаны с этой ответственностью.
  6. Полиморфизм (Polymorphism): Для обработки альтернативных вариантов поведения на основе типа следует использовать полиморфные операции (интерфейсы, абстрактные классы).
  7. Чистая выдумка (Pure Fabrication): Если ни один из существующих классов не подходит по принципам High Cohesion и Low Coupling, можно создать искусственный, "сервисный" класс.
  8. Посредник (Indirection): Для уменьшения прямой связанности между компонентами следует ввести промежуточный объект-посредник.
  9. Устойчивость к изменениям (Protected Variations): Выделять точки потенциальной изменчивости и инкапсулировать их за стабильным интерфейсом.

Пример "Информационный эксперт":

class ShoppingCart {
    private List<Item> items; // Данные о товарах здесь

    // Этот класс — "эксперт" по данным корзины, поэтому он вычисляет итог.
    public double calculateTotal() {
        return items.stream()
                    .mapToDouble(item -> item.getPrice() * item.getQuantity())
                    .sum();
    }
}