Какие паттерны проектирования вы знаете?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Какие паттерны проектирования вы знаете?
Паттерны проектирования — это проверенные решения типичных проблем разработки. Они делятся на три категории: порождающие (создание объектов), структурные (композиция объектов) и поведенческие (взаимодействие объектов).
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 принципы?
- Примеры паттернов из реального кода