Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Паттерны проектирования (Design Patterns)
Паттерны — это проверенные, переиспользуемые решения для типичных проблем в разработке. Это не код, а описание подхода к организации кода, которое помогает решать задачи проще, быстрее и с меньшей вероятностью ошибок.
Почему нужны паттерны
1. Реиспользование опыта
Без паттернов: каждый разработчик решает одну и ту же проблему по-своему
С паттернами: используем решение, проверенное тысячами разработчиков
Это как архитектурные стили в зданиях:
- Зачем изобретать новый стиль, если готика уже доказала свою прочность?
2. Общий язык в команде
Без паттернов:
Коллега: "Как здесь работает кэширование?"
Ты: "Ну, там есть словарь, потом проверяем..."
С паттернами:
Коллега: "Здесь используется Singleton?"
Ты: "Да, для управления подключением к БД"
(Коллега сразу понимает архитектуру)
3. Качество и надежность кода
Паттерны прошли тестирование временем и в боевых условиях
Они учитывают edge cases, которые ты можешь упустить
Использование паттернов снижает количество багов
Основные категории паттернов
Порождающие (Creational) — как создавать объекты
Singleton: один экземпляр на все приложение
class DatabaseConnection:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance.connect()
return cls._instance
def connect(self):
print('Connecting to database...')
# Будет только одно соединение
db1 = DatabaseConnection()
db2 = DatabaseConnection()
print(db1 is db2) # True — один и тот же объект
Factory: создание объектов через фабрику
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def make_sound(self):
pass
class Dog(Animal):
def make_sound(self):
return 'Woof'
class Cat(Animal):
def make_sound(self):
return 'Meow'
class AnimalFactory:
@staticmethod
def create_animal(animal_type):
if animal_type == 'dog':
return Dog()
elif animal_type == 'cat':
return Cat()
raise ValueError(f'Unknown animal: {animal_type}')
# Вместо: animal = Dog()
# Используем фабрику
animal = AnimalFactory.create_animal('dog')
print(animal.make_sound()) # Woof
Builder: создание сложных объектов пошагово
class SQLQuery:
def __init__(self):
self.select = []
self.where = []
self.order_by = []
def add_select(self, *columns):
self.select.extend(columns)
return self
def add_where(self, condition):
self.where.append(condition)
return self
def add_order_by(self, column):
self.order_by.append(column)
return self
def build(self):
query = f"SELECT {', '.join(self.select)}"
if self.where:
query += f" WHERE {' AND '.join(self.where)}"
if self.order_by:
query += f" ORDER BY {', '.join(self.order_by)}"
return query
# Построение запроса пошагово
query = SQLQuery()\
.add_select('id', 'name', 'email')\
.add_where('age > 18')\
.add_where('status = active')\
.add_order_by('name')\
.build()
print(query)
# SELECT id, name, email WHERE age > 18 AND status = active ORDER BY name
Структурные (Structural) — как организовать отношения между объектами
Adapter: преобразование несовместимого интерфейса
class OldWeatherAPI:
def get_temp(self):
return {'celsius': 25} # Возвращает Цельсии
class NewWeatherAPI:
def get_temperature(self):
return 77 # Возвращает Фаренгейты
class WeatherAdapter:
def __init__(self, old_api):
self.api = old_api
def get_temperature(self):
celsius = self.api.get_temp()['celsius']
fahrenheit = (celsius * 9/5) + 32
return fahrenheit
# Адаптируем старый API под новый интерфейс
adapted = WeatherAdapter(OldWeatherAPI())
print(adapted.get_temperature()) # 77
Decorator: добавление функциональности к объекту
class Coffee:
def cost(self):
return 100
def description(self):
return 'Coffee'
class MilkDecorator:
def __init__(self, coffee):
self.coffee = coffee
def cost(self):
return self.coffee.cost() + 50
def description(self):
return self.coffee.description() + ' with Milk'
class SugarDecorator:
def __init__(self, coffee):
self.coffee = coffee
def cost(self):
return self.coffee.cost() + 20
def description(self):
return self.coffee.description() + ' with Sugar'
# Комбинируем декораторы
coffee = Coffee()
coffee = MilkDecorator(coffee)
coffee = SugarDecorator(coffee)
print(coffee.description()) # Coffee with Milk with Sugar
print(coffee.cost()) # 170
Facade: упрощение сложной системы
class OrderSystem:
def check_inventory(self, item):
return True
def process_payment(self, amount):
return True
def create_shipment(self, address):
return True
class OrderFacade:
def __init__(self):
self.system = OrderSystem()
def place_order(self, item, amount, address):
# Скрываем сложность системы
if not self.system.check_inventory(item):
return False
if not self.system.process_payment(amount):
return False
return self.system.create_shipment(address)
# Клиент использует простой интерфейс
facade = OrderFacade()
facade.place_order('book', 299, 'Moscow')
Поведенческие (Behavioral) — как организовать взаимодействие между объектами
Observer: подписка на события
class EventEmitter:
def __init__(self):
self.listeners = {}
def on(self, event, callback):
if event not in self.listeners:
self.listeners[event] = []
self.listeners[event].append(callback)
def emit(self, event, data):
if event in self.listeners:
for callback in self.listeners[event]:
callback(data)
# Использование
emitter = EventEmitter()
def on_user_registered(user):
print(f'Email sent to {user}')
def on_user_logged(user):
print(f'Analytics logged for {user}')
emitter.on('user_registered', on_user_registered)
emitter.on('user_registered', on_user_logged)
emitter.emit('user_registered', 'alice@example.com')
# Email sent to alice@example.com
# Analytics logged for alice@example.com
Strategy: выбор алгоритма в runtime
from abc import ABC, abstractmethod
class PaymentStrategy(ABC):
@abstractmethod
def pay(self, amount):
pass
class CreditCardPayment(PaymentStrategy):
def pay(self, amount):
return f'Paid {amount} with credit card'
class PayPalPayment(PaymentStrategy):
def pay(self, amount):
return f'Paid {amount} with PayPal'
class CryptoCurrencyPayment(PaymentStrategy):
def pay(self, amount):
return f'Paid {amount} with crypto'
class ShoppingCart:
def __init__(self, payment_strategy: PaymentStrategy):
self.strategy = payment_strategy
def checkout(self, amount):
return self.strategy.pay(amount)
# Выбираем стратегию в runtime
cart = ShoppingCart(CreditCardPayment())
print(cart.checkout(100))
cart = ShoppingCart(PayPalPayment())
print(cart.checkout(100))
Chain of Responsibility: передача запроса по цепи
class Handler:
def __init__(self):
self.next_handler = None
def set_next(self, handler):
self.next_handler = handler
return handler
def handle(self, request):
if self.next_handler:
return self.next_handler.handle(request)
return None
class LoggingHandler(Handler):
def handle(self, request):
print(f'Logging: {request}')
return super().handle(request)
class ValidationHandler(Handler):
def handle(self, request):
if not request:
return 'Invalid request'
print(f'Validating: {request}')
return super().handle(request)
class ProcessingHandler(Handler):
def handle(self, request):
print(f'Processing: {request}')
return 'Done'
# Выстраиваем цепь
logger = LoggingHandler()
validator = ValidationHandler()
processor = ProcessingHandler()
logger.set_next(validator).set_next(processor)
logger.handle('user_registration')
# Logging: user_registration
# Validating: user_registration
# Processing: user_registration
Когда использовать паттерны
✅ Используй когда:
# 1. Нужно управлять только одним экземпляром
class DatabaseConnection: # Singleton
pass
# 2. Нужна гибкость в создании объектов
class DataSourceFactory: # Factory
pass
# 3. Нужно обработать несколько вариантов
if user_type == 'premium':
strategy = PremiumStrategy()
else:
strategy = BasicStrategy() # Strategy
# 4. Нужно расширить функциональность
user = User() # Decorator
user = LoggingDecorator(user)
❌ Не используй когда:
# 1. Проблема простая
# ❌ Не нужно Factory для простого создания
from helpers import create_user
# 2. Добавляет complexity без пользы
# ❌ Паттерн усложняет код
# 3. Это YAGNI (You Ain't Gonna Need It)
# ❌ Добавляешь паттерн "на будущее"
Итоговое правило
Паттерны нужны чтобы:
- Решать типичные проблемы проверенными методами
- Делать код более понятным и поддерживаемым
- Облегчать коммуникацию в команде
- Снижать вероятность ошибок
Но помни:
- Паттерн — это средство, не цель
- Не применяй паттерн просто потому что он красивый
- Простой код лучше, чем сложный паттерн
- Изучай паттерны, но не переиспользуй их