← Назад к вопросам

Что такое GRASP?

2.7 Senior🔥 91 комментариев
#Архитектура и паттерны

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое GRASP

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

Девять принципов GRASP

1. Information Expert (Информационный эксперт)

Ответственность должна быть у объекта, у которого есть информация.

# Плохо: Calculator знает о структуре Sale
class Calculator:
    def calculate_total(self, sale):
        total = 0
        for item in sale.items:
            total += item.price * item.quantity
        return total

# Хорошо: Sale сам знает о своей структуре
class Sale:
    def __init__(self):
        self.items = []
    
    def calculate_total(self):
        return sum(item.price * item.quantity for item in self.items)

sale = Sale()
sale.items.append(Item(price=100, quantity=2))
print(sale.calculate_total())  # 200

2. Creator (Создатель)

Ответственность за создание объекта должна быть у класса, который содержит или использует создаваемый объект.

# Плохо: Order создаёт User
class Order:
    def __init__(self):
        self.user = User()  # Странно

# Хорошо: OrderService создаёт Order
class OrderService:
    def create_order(self, user_id):
        order = Order(user_id=user_id)
        return order

class Order:
    def __init__(self, user_id):
        self.user_id = user_id

3. Controller (Контроллер)

Ответственность за координацию системы должна быть у объекта, который координирует.

# API endpoint — Controller
@router.post("/orders")
async def create_order_controller(order_data: OrderCreate):
    # Контроллер координирует
    service = OrderService()
    order = service.create(order_data)
    return {"id": order.id}

# Бизнес-логика — Service
class OrderService:
    def create(self, order_data):
        order = Order(data=order_data)
        # Бизнес-логика
        return order

4. Low Coupling (Низкая связанность)

Минимизируй зависимости между классами.

# Плохо: PaymentProcessor зависит от конкретного Payment
class PaymentProcessor:
    def process(self, payment: StripePayment):
        return payment.charge()

# Хорошо: используй интерфейс
class PaymentProcessor:
    def process(self, payment: PaymentProvider):
        return payment.charge()

# Можешь использовать любого провайдера
class StripePayment(PaymentProvider):
    def charge(self):
        pass

class PayPalPayment(PaymentProvider):
    def charge(self):
        pass

5. High Cohesion (Высокая связность)

Одноответственность класса. Все методы класса работают на одну цель.

# Плохо: User отвечает за слишком многое
class User:
    def send_email(self):
        pass
    
    def log_activity(self):
        pass
    
    def calculate_discount(self):
        pass
    
    def process_payment(self):
        pass

# Хорошо: разделение ответственности
class User:
    def __init__(self, id, email):
        self.id = id
        self.email = email

class EmailService:
    def send_email(self, user):
        pass

class ActivityLogger:
    def log(self, user, activity):
        pass

class DiscountCalculator:
    def calculate(self, user):
        pass

class PaymentProcessor:
    def process(self, user, amount):
        pass

6. Polymorphism (Полиморфизм)

Используй полиморфизм вместо условной логики.

# Плохо: много if/else
class PaymentHandler:
    def handle(self, payment_type, amount):
        if payment_type == 'credit_card':
            # обработка кредитки
            pass
        elif payment_type == 'paypal':
            # обработка PayPal
            pass
        elif payment_type == 'bank_transfer':
            # обработка банка
            pass

# Хорошо: полиморфизм
class PaymentHandler(ABC):
    @abstractmethod
    def handle(self, amount):
        pass

class CreditCardHandler(PaymentHandler):
    def handle(self, amount):
        print(f"Processing credit card: {amount}")

class PayPalHandler(PaymentHandler):
    def handle(self, amount):
        print(f"Processing PayPal: {amount}")

class BankTransferHandler(PaymentHandler):
    def handle(self, amount):
        print(f"Processing bank transfer: {amount}")

# Использование
handlers = {
    'credit_card': CreditCardHandler(),
    'paypal': PayPalHandler(),
    'bank': BankTransferHandler()
}

handler = handlers[payment_type]
handler.handle(amount)  # Работает для любого типа

7. Pure Fabrication (Чистая выдумка)

Создавай объекты для решения проблемы с низкой связанностью, даже если они не соответствуют доменной модели.

# Пример: класс Service создан не в домене, но нужен для логики
class OrderRepository:  # Pure Fabrication — не в домене
    def save(self, order):
        pass
    
    def find_by_id(self, id):
        pass

# Это не физический объект, но нужен для хранения заказов

8. Indirection (Косвенность)

Используй промежуточный объект для разделения связанности.

# Плохо: Service напрямую зависит от DB
class OrderService:
    def __init__(self):
        self.db = DatabaseConnection()
    
    def create_order(self, data):
        self.db.insert('orders', data)

# Хорошо: используй Repository как посредник
class OrderService:
    def __init__(self, repository):
        self.repository = repository  # Инъекция зависимости
    
    def create_order(self, data):
        order = Order(data)
        self.repository.save(order)

class OrderRepository:
    def __init__(self, db):
        self.db = db
    
    def save(self, order):
        self.db.insert('orders', order.to_dict())

9. Protected Variations (Защита вариаций)

Изолируй то, что может меняться.

# Плохо: коды валют hardcoded везде
class Payment:
    def calculate_tax(self, amount):
        if currency == 'USD':
            return amount * 0.1
        elif currency == 'EUR':
            return amount * 0.2

# Хорошо: вынеси в конфиг или сервис
class TaxCalculator:
    def __init__(self, currency_config):
        self.config = currency_config
    
    def calculate_tax(self, amount, currency):
        tax_rate = self.config.get_tax_rate(currency)
        return amount * tax_rate

config = {
    'USD': 0.1,
    'EUR': 0.2
}

Практический пример: система управления заказами

# Применяем GRASP принципы

from abc import ABC, abstractmethod

# 1. Information Expert
class Order:
    def __init__(self, items):
        self.items = items
    
    def calculate_total(self):  # Order знает о своей структуре
        return sum(item.price * item.quantity for item in self.items)

# 2-3. Creator и Controller
class OrderService:
    def __init__(self, repository):
        self.repository = repository
    
    def create_order(self, items):
        order = Order(items)
        self.repository.save(order)
        return order

# 4-5. Low Coupling и High Cohesion
class OrderRepository:  # Pure Fabrication для работы с БД
    def __init__(self, db):
        self.db = db  # Косвенность
    
    def save(self, order):
        self.db.insert('orders', order.to_dict())

# 6. Polymorphism
class PaymentProvider(ABC):
    @abstractmethod
    def charge(self, amount):
        pass

class StripePayment(PaymentProvider):
    def charge(self, amount):
        print(f"Charging Stripe: {amount}")

class PayPalPayment(PaymentProvider):
    def charge(self, amount):
        print(f"Charging PayPal: {amount}")

# 9. Protected Variations
class PaymentFactory:
    def create_payment(self, provider_type):
        providers = {
            'stripe': StripePayment(),
            'paypal': PayPalPayment()
        }
        return providers[provider_type]

Как GRASP помогает

  • Читаемость: Код понятен, ответственности ясны
  • Поддерживаемость: Легко изменять части системы
  • Масштабируемость: Новые фичи добавляются просто
  • Тестируемость: Легко писать юнит-тесты
  • Переиспользуемость: Компоненты независимы

Вывод: GRASP — это не конкретные паттерны, а принципы проектирования. Они помогают распределить ответственность правильно и написать гибкий, поддерживаемый код.