Identity Map

Одна сущность — один объект

Идея паттерна

Identity Map хранит карту уже загруженных сущностей по идентификатору, чтобы при повторных запросах возвращать тот же объект, избегая дубликатов и лишних обращений к БД.
class IdentityMap:
    def __init__(self):
        self._map = {}
    def get(self, cls, id_):
        return self._map.get((cls, id_))
    def add(self, cls, id_, obj):
        self._map[(cls, id_)] = obj

identity_map = IdentityMap()

class UserRepository:
    def __init__(self, db):
        self.db = db
    def find_by_id(self, id_: int):
        cached = identity_map.get('User', id_)
        if cached:
            return cached
        row = self.db.fetch_one("SELECT id,name,email FROM users WHERE id=?", (id_,))
        if not row:
            return None
        user = User(id=row['id'], name=row['name'], email=row['email'])
        identity_map.add('User', id_, user)
        return user

Зачем это нужно

  • ✅ Избегание дубликатов объектов (согласованность графа объектов)
  • ✅ Производительность (меньше обращений к БД)
  • ✅ Ссылочная целостность в памяти (User у Order и у Service — один объект)

Подводные камни

  • ❌ Сложности с жизненным циклом/очисткой карты
  • ❌ Утечки памяти при долгоживущих картах
  • ❌ Согласованность при конкурентных изменениях

Связь с Unit of Work/ORM

  • ORM (SQLAlchemy, Django ORM) используют Identity Map внутри сессии
  • Совместно с Unit of Work обеспечивает трекинг изменений и фиксирование состояния