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

Ответ

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

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

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

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

Класс Order является информационным экспертом для расчета общей стоимости, так как он владеет списком items и их свойствами.

class Item:
    def __init__(self, price: float, quantity: int):
        self.price = price
        self.quantity = quantity

class Order:
    def __init__(self, items: list[Item]):
        self.items = items

    def calculate_total(self) -> float:
        """Рассчитывает общую стоимость заказа."""
        # Order знает свои items, поэтому логично считать сумму здесь
        return sum(item.price * item.quantity for item in self.items)

# Использование:
item1 = Item(price=10.0, quantity=2)
item2 = Item(price=5.5, quantity=3)
order = Order(items=[item1, item2])
print(f"Общая стоимость заказа: {order.calculate_total():.2f}") # Вывод: 36.50

Применение GRASP-паттернов помогает создавать более гибкие, понятные и легко поддерживаемые объектно-ориентированные системы, улучшая их архитектуру и качество кода.