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

Какие паттерны проектирования вы знаете?

2.0 Middle🔥 201 комментариев
#DevOps и инфраструктура#Django

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

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

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

Какие паттерны проектирования вы знаете?

Паттерны проектирования — это проверенные решения типичных проблем разработки. Они делятся на три категории: порождающие (создание объектов), структурные (композиция объектов) и поведенческие (взаимодействие объектов).

1. Порождающие паттерны (Creational)

Отвечают за создание объектов

1.1 Singleton (Одиночка)

class Database:
    _instance = None
    
    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
            cls._instance.connection = None
        return cls._instance
    
    def connect(self):
        if not self.connection:
            self.connection = "Connected to DB"
        return self.connection

# Использование
db1 = Database()
db2 = Database()
print(db1 is db2)  # True — один объект
print(db1.connect())

Когда использовать: БД, логирование, конфигурация

1.2 Factory Method (Фабрика)

from abc import ABC, abstractmethod

class Transport(ABC):
    @abstractmethod
    def deliver(self):
        pass

class Truck(Transport):
    def deliver(self):
        return "Delivering by truck"

class Ship(Transport):
    def deliver(self):
        return "Delivering by ship"

class Logistics(ABC):
    @abstractmethod
    def create_transport(self) -> Transport:
        pass
    
    def plan_delivery(self):
        transport = self.create_transport()
        return transport.deliver()

class RoadLogistics(Logistics):
    def create_transport(self) -> Transport:
        return Truck()

class SeaLogistics(Logistics):
    def create_transport(self) -> Transport:
        return Ship()

# Использование
logistics = RoadLogistics()
print(logistics.plan_delivery())  # "Delivering by truck"

Когда использовать: Когда класс не знает, какой подкласс создавать

1.3 Builder (Строитель)

class House:
    def __init__(self):
        self.walls = None
        self.roof = None
        self.door = None
        self.windows = None

class HouseBuilder:
    def __init__(self):
        self.house = House()
    
    def build_walls(self):
        self.house.walls = "Brick walls"
        return self
    
    def build_roof(self):
        self.house.roof = "Tile roof"
        return self
    
    def build_door(self):
        self.house.door = "Wooden door"
        return self
    
    def build_windows(self):
        self.house.windows = "Glass windows"
        return self
    
    def build(self) -> House:
        return self.house

# Использование (fluent interface)
house = (HouseBuilder()
    .build_walls()
    .build_roof()
    .build_door()
    .build_windows()
    .build())

Когда использовать: Сложные объекты с множеством параметров

2. Структурные паттерны (Structural)

Отвечают за композицию и отношения между объектами

2.1 Decorator (Декоратор)

from abc import ABC, abstractmethod

class Coffee(ABC):
    @abstractmethod
    def cost(self):
        pass

class SimpleCoffee(Coffee):
    def cost(self):
        return 100

class CoffeeDecorator(Coffee):
    def __init__(self, coffee: Coffee):
        self.coffee = coffee
    
    def cost(self):
        return self.coffee.cost()

class MilkDecorator(CoffeeDecorator):
    def cost(self):
        return super().cost() + 50

class SugarDecorator(CoffeeDecorator):
    def cost(self):
        return super().cost() + 10

# Использование
coffee = SimpleCoffee()
coffee = MilkDecorator(coffee)
coffee = SugarDecorator(coffee)
print(coffee.cost())  # 160

Когда использовать: Добавление поведения объектам динамически

2.2 Adapter (Адаптер)

class OldPaymentSystem:
    def pay(self, amount):
        return f"Paid {amount} using old system"

class NewPaymentSystem:
    def process_payment(self, amount):
        pass

class PaymentAdapter(NewPaymentSystem):
    def __init__(self, old_system: OldPaymentSystem):
        self.old_system = old_system
    
    def process_payment(self, amount):
        return self.old_system.pay(amount)

# Использование
old = OldPaymentSystem()
adapter = PaymentAdapter(old)
print(adapter.process_payment(100))

Когда использовать: Интеграция несовместимых интерфейсов

2.3 Proxy (Прокси)

from abc import ABC, abstractmethod

class Image(ABC):
    @abstractmethod
    def display(self):
        pass

class RealImage(Image):
    def __init__(self, filename):
        self.filename = filename
        self.load()
    
    def load(self):
        print(f"Loading {self.filename}")
    
    def display(self):
        print(f"Displaying {self.filename}")

class ProxyImage(Image):
    def __init__(self, filename):
        self.filename = filename
        self.real_image = None
    
    def display(self):
        if self.real_image is None:
            self.real_image = RealImage(self.filename)
        self.real_image.display()

# Использование (ленивая загрузка)
image = ProxyImage("photo.jpg")
image.display()  # Загружает только при вызове display()

Когда использовать: Контроль доступа, ленивая загрузка, логирование

3. Поведенческие паттерны (Behavioral)

Отвечают за взаимодействие объектов и распределение ответственности

3.1 Observer (Наблюдатель)

from abc import ABC, abstractmethod
from typing import List

class Observer(ABC):
    @abstractmethod
    def update(self, data):
        pass

class Subject:
    def __init__(self):
        self._observers: List[Observer] = []
    
    def attach(self, observer: Observer):
        self._observers.append(observer)
    
    def detach(self, observer: Observer):
        self._observers.remove(observer)
    
    def notify(self, data):
        for observer in self._observers:
            observer.update(data)

class NewsChannel(Subject):
    def publish(self, news):
        print(f"News published: {news}")
        self.notify(news)

class Subscriber(Observer):
    def __init__(self, name):
        self.name = name
    
    def update(self, data):
        print(f"{self.name} received: {data}")

# Использование
channel = NewsChannel()
sub1 = Subscriber("Alice")
sub2 = Subscriber("Bob")
channel.attach(sub1)
channel.attach(sub2)
channel.publish("Breaking news!")

Когда использовать: Event-driven архитектура, MVC паттерн

3.2 Strategy (Стратегия)

from abc import ABC, abstractmethod

class SortingStrategy(ABC):
    @abstractmethod
    def sort(self, data: list):
        pass

class QuickSort(SortingStrategy):
    def sort(self, data: list):
        return sorted(data)  # Упрощено

class MergeSort(SortingStrategy):
    def sort(self, data: list):
        return sorted(data)  # Упрощено

class Sorter:
    def __init__(self, strategy: SortingStrategy):
        self.strategy = strategy
    
    def do_sort(self, data: list):
        return self.strategy.sort(data)

# Использование
data = [5, 2, 8, 1]
sorter = Sorter(QuickSort())
print(sorter.do_sort(data))

Когда использовать: Выбор алгоритма во время выполнения

3.3 Command (Команда)

from abc import ABC, abstractmethod

class Command(ABC):
    @abstractmethod
    def execute(self):
        pass
    
    @abstractmethod
    def undo(self):
        pass

class Light:
    def on(self):
        return "Light is on"
    
    def off(self):
        return "Light is off"

class TurnOnCommand(Command):
    def __init__(self, light: Light):
        self.light = light
    
    def execute(self):
        return self.light.on()
    
    def undo(self):
        return self.light.off()

class RemoteControl:
    def __init__(self):
        self.command = None
    
    def set_command(self, command: Command):
        self.command = command
    
    def press_button(self):
        return self.command.execute()
    
    def press_undo(self):
        return self.command.undo()

# Использование
light = Light()
remote = RemoteControl()
remote.set_command(TurnOnCommand(light))
print(remote.press_button())  # Light is on

Когда использовать: Undo/Redo, очереди команд, макросы

3.4 State (Состояние)

from abc import ABC, abstractmethod

class State(ABC):
    @abstractmethod
    def handle(self, context):
        pass

class IdleState(State):
    def handle(self, context):
        return "System is idle"

class RunningState(State):
    def handle(self, context):
        return "System is running"

class System:
    def __init__(self):
        self.state = IdleState()
    
    def set_state(self, state: State):
        self.state = state
    
    def request(self):
        return self.state.handle(self)

# Использование
system = System()
print(system.request())  # System is idle
system.set_state(RunningState())
print(system.request())  # System is running

Когда использовать: State machines, конечные автоматы

Таблица паттернов

ТипПаттернРешаетКогда
PorождающийSingletonОдин объектБД, логирование
ПорождающийFactoryСоздание объектовНеизвестны типы
ПорождающийBuilderСложные объектыМного параметров
СтруктурныйDecoratorДобавление поведенияДинамическое расширение
СтруктурныйAdapterНесовместимые интерфейсыИнтеграция
СтруктурныйProxyКонтроль доступаЛенивая загрузка
ПоведенческийObserverСлабая связанностьEvents
ПоведенческийStrategyВыбор алгоритмаРазные реализации
ПоведенческийCommandИнкапсуляция операцийUndo/Redo
ПоведенческийStateУправление состояниямиState machines

Какие паттерны использованы в популярных библиотеках

# Django ORM — Repository паттерн
User.objects.filter(age__gte=18)

# Flask — Strategy паттерн
app.route("/users")  # Стратегия маршрутизации

# SQLAlchemy — Active Record паттерн
user.save()

# asyncio — Observer паттерн
asynci.run()

# Logging — Singleton паттерн
import logging
logger = logging.getLogger(__name__)

Когда НЕ использовать паттерны

  • YAGNI (You Aren't Gonna Need It) — не усложняй без причины
  • Избегай паттернов "для галочки"
  • Используй только когда решают реальную проблему

Интервьюерские вопросы

  • Разница между Decorator и Proxy?
  • Когда использовать Factory вместо Builder?
  • Зачем нужны паттерны?
  • Как паттерны нарушают SOLID принципы?
  • Примеры паттернов из реального кода