Обзор паттернов проектирования: Singleton, Factory, Observer
В этой статье я расскажу тебе про несколько самых полезных паттернов на Python. Готов? Поехали!
Паттерн Singleton
Первый паттерн, который стоит выучить - Singleton. Он нужен, когда в программе должен быть только один экземпляр какого-то класса. Например, класс настроек приложения.
Singleton гарантирует, что у тебя будет только один объект этого класса. Вот пример кода:
class Settings: _instance = None def __new__(cls): if cls._instance is None: cls._instance = super().__new__(cls) return cls._instance
Здесь мы создали класс Settings
и переопределили метод __new__
. Он вызывается при создании нового объекта. Мы проверяем, существует ли уже экземпляр в _instance
. Если нет - создаем. Если есть - возвращаем существующий.
Таким образом, сколько бы раз мы не вызывали Settings()
, у нас будет только один объект. Проверим:
s1 = Settings() s2 = Settings() print(s1 == s2) # True - объект один и тот же
Как видишь, Singleton - простой и полезный паттерн, чтобы иметь только один экземпляр класса.
Паттерн Factory
Следующий важный паттерн - Factory (Фабрика). Он нужен, когда у тебя много похожих классов, и ты хочешь упростить их создание.
Например, в игре у тебя есть классы Goblin
, Skeleton
, Orc
- разных монстров. Чтобы не писать в коде goblin = Goblin()
, skeleton = Skeleton()
и т.д., можно сделать фабрику:
class MonsterFactory: def create_monster(self, type): if type == "goblin": return Goblin() elif type == "skeleton": return Skeleton() elif type == "orc": return Orc() factory = MonsterFactory() monster = factory.create_monster("skeleton")
Теперь, чтобы создать монстра, достаточно вызвать метод create_monster
и указать тип. Код становится чище и проще для понимания.
Паттерн Factory - очень удобный способ создавать схожие объекты в одном месте, не засоряя код.
Паттерн Observer
Еще один полезный паттерн - Observer (Наблюдатель). Он нужен, когда объекты в программе должны реагировать на изменения в других объектах.
Представь, в игре у тебя есть юниты и здания. И юниты должны автоматически атаковать вражеские здания, когда те появляются.
Мы можем сделать это с Observer:
from __future__ import annotations from abc import ABC, abstractmethod from random import randint class Observable(ABC): def __init__(self): self.observers = [] def notify(self): for observer in self.observers: observer.update(self) def attach(self, observer): self.observers.append(observer) class Observer(ABC): @abstractmethod def update(self, subject: Observable) -> None: pass class Unit(Observer): def update(self, building: Building): print(f"Unit is attacking {building}") building.hp -= randint(1, 10) class Building(Observable): def __init__(self): super().__init__() self.hp = 100 # Использование building = Building() unit = Unit() building.attach(unit) building.notify() # Unit attacks building
Здесь Building
наследует от Observable
и может уведомлять наблюдателей о событиях через notify()
. А Unit
реализует интерфейс Observer
и получает уведомления в методе update()
.
Таким образом юниты могут автоматически реагировать на появление зданий. Это и есть Observer - мощный паттерн для реакции объектов друг на друга.
Другие паттерны
Я рассказал про самые важные паттерны. Но есть и другие полезные:
Command - помещает задачи в объекты-команды для многократного выполнения или отмены.
Strategy - позволяет легко переключать разные алгоритмы решения задачи.
Decorator - добавляет объектам новое поведение без изменения кода.
Все эти паттерны тоже пригодятся в больших проектах. Поэтому стоит разобраться с ними, когда появится время.
Итог
Ну вот мы и разобрали основные паттерны проектирования на Python. Как видишь, это очень полезные и мощные инструменты. Они помогут тебе писать правильный, гибкий и поддерживаемый код. А это ключевое умение для профессионального программиста.