ГлавнаяБлогПроектирование LLD: от требований к коду на Python
Алгоритмы

Проектирование LLD: от требований к коду на Python

Пошаговое руководство по Low-Level Design: анализ требований, выделение классов, наследование, композиция и код на Python. Начни проектировать правильно!

Al
Редакция Algolitalgolit.ru
12 мин чтения19 июня 2026 г.

Зачем нужно проектирование LLD?

Когда вы пишете код без плана, рано или поздно он превращается в спагетти. Low-Level Design (LLD) — это мост между требованиями и чистым, расширяемым кодом. В этой статье вы пройдёте 8 шагов от анализа требований до готового кода на Python. На примере редактора документов и парковки вы научитесь выделять классы, строить иерархии и применять композицию. Готовы? Поехали!

Шаг 1: Понимание требований

Прежде чем создавать классы, чётко поймите, что должна делать система. Задайте вопросы:

  • Какие функции обязательны?
  • Какие операции поддерживаются?
  • Какие расширения возможны в будущем?

Пример: Редактор документов

Требования:

  • Добавить текст
  • Добавить изображение
  • Новая строка
  • Табуляция
  • Отрендерить документ
  • Сохранить документ

Никогда не прыгайте сразу к классам. Сначала поймите задачу.

Шаг 2: Извлекаем существительные → классы

Существительные из требований часто становятся классами.

Пример:

  • Существительные: Документ, Текст, Изображение, Хранилище, Редактор
  • Кандидаты в классы: Document, TextElement, ImageElement, Storage, DocumentEditor

Другой пример: Парковка

  • Требования: припарковать машину, выдать талон, несколько этажей
  • Существительные: Парковка, Этаж, Место, Машина, Талон
  • Классы: ParkingLot, Floor, Slot, Vehicle, Ticket

Шаг 3: Ищем отношения IS-A → наследование

Спросите: «Можно ли сказать, что дочерний класс ЯВЛЯЕТСЯ родительским?»

Пример:

  • TextElement IS-A DocumentElement
  • ImageElement IS-A DocumentElement
  • NewLineElement IS-A DocumentElement
  • TabSpaceElement IS-A DocumentElement

Иерархия:

DocumentElement
    ▲
    |
----------------------------------
|         |          |           |
TextElement ImageElement NewLineElement TabSpaceElement

Код на Python:

from abc import ABC, abstractmethod

class DocumentElement(ABC):
    @abstractmethod
    def render(self) -> str:
        pass

class TextElement(DocumentElement):
    def __init__(self, text: str):
        self.text = text
    def render(self) -> str:
        return self.text

class ImageElement(DocumentElement):
    def __init__(self, src: str):
        self.src = src
    def render(self) -> str:
        return f'<img src="{self.src}" />'

Правило: используйте наследование только когда дочерний класс ЯВЛЯЕТСЯ родительским. Примеры: Car IS-A Vehicle, Dog IS-A Animal, CreditCardPayment IS-A Payment.

Шаг 4: Ищем отношения HAS-A → композиция/агрегация

Спросите: «Какие объекты содержатся внутри другого объекта?»

Пример: документ содержит элементы.

class Document:
    def __init__(self):
        self.elements: list[DocumentElement] = []

Это означает: Document HAS-A collection of DocumentElement.

Другой пример: ParkingLot HAS-A Floor, Floor HAS-A Slot.

Правило: используйте композицию/агрегацию когда родитель ИМЕЕТ дочерний объект. Примеры: Car HAS-A Engine, Document HAS-A Elements.

Шаг 5: Определяем действия → методы

Спросите: «Какие действия могут выполнять объекты?»

Пример редактора документов:

  • Действия: добавить текст, добавить изображение, отрендерить, сохранить
  • Методы: add_text(), add_image(), render(), save()

Пример парковки:

  • Действия: припарковать, выдать талон
  • Методы: park_vehicle(), unpark_vehicle(), generate_ticket()

Правило: глаголы становятся методами. Существительные → классы, глаголы → методы.

Шаг 6: Ищем вариации → интерфейсы/абстрактные классы

Спросите: «Что может измениться в будущем?»

Пример сохранения документа: файл, база данных, облако. Это разные реализации. Создаём абстракцию:

class Persistence(ABC):
    @abstractmethod
    def save(self, data: str) -> None:
        pass

class FileStorage(Persistence):
    def save(self, data: str) -> None:
        with open('document.txt', 'w') as f:
            f.write(data)

class DBStorage(Persistence):
    def save(self, data: str) -> None:
        # сохранение в БД
        pass

Завтра мы можем добавить CloudStorage, не меняя существующий код.

Правило: когда есть несколько реализаций, создайте интерфейс/абстрактный класс. Примеры: Payment (UPI, Card, Cash), Storage (File, DB, Cloud), Notification (Email, SMS, Push).

Шаг 7: Рисуем UML

После определения классов, методов, наследования и композиции нарисуйте диаграмму классов UML.

Пример для редактора:

Document
    |
    | содержит
    v
DocumentElement
      ▲
      |
-----------------------
|         |           |
Text    Image     NewLine

Persistence
      ▲
      |
---------------
|             |
FileStorage DBStorage

Шаг 8: Пишем код

Преобразуйте UML в код на Python. Полный пример:

from abc import ABC, abstractmethod

# Абстрактный класс элемента документа
class DocumentElement(ABC):
    @abstractmethod
    def render(self) -> str:
        pass

# Конкретные элементы
class TextElement(DocumentElement):
    def __init__(self, text: str):
        self.text = text
    def render(self) -> str:
        return self.text

class ImageElement(DocumentElement):
    def __init__(self, src: str):
        self.src = src
    def render(self) -> str:
        return f'<img src="{self.src}" />'

class NewLineElement(DocumentElement):
    def render(self) -> str:
        return '\n'

class TabSpaceElement(DocumentElement):
    def render(self) -> str:
        return '\t'

# Композиция: документ содержит элементы
class Document:
    def __init__(self):
        self.elements: list[DocumentElement] = []

    def add_element(self, element: DocumentElement) -> None:
        self.elements.append(element)

    def render(self) -> str:
        return ''.join(el.render() for el in self.elements)

# Абстракция сохранения
class Persistence(ABC):
    @abstractmethod
    def save(self, data: str) -> None:
        pass

class FileStorage(Persistence):
    def save(self, data: str) -> None:
        with open('document.txt', 'w') as f:
            f.write(data)

# Редактор с внедрением зависимости
class DocumentEditor:
    def __init__(self, storage: Persistence):
        self.doc = Document()
        self.storage = storage

    def add_text(self, text: str) -> None:
        self.doc.add_element(TextElement(text))

    def add_image(self, src: str) -> None:
        self.doc.add_element(ImageElement(src))

    def save(self) -> None:
        rendered = self.doc.render()
        self.storage.save(rendered)

# Пример использования
if __name__ == '__main__':
    storage = FileStorage()
    editor = DocumentEditor(storage)
    editor.add_text('Привет, мир!')
    editor.add_image('logo.png')
    editor.save()
    print(editor.doc.render())

Практический вывод

Теперь, когда вы знаете 8 шагов LLD, примените их на практике. Возьмите любую задачу (например, проектирование корзины интернет-магазина) и пройдите шаги: требования → существительные → классы → IS-A → HAS-A → методы → вариации → UML → код. Чем больше практики, тем быстрее вы будете проектировать чистые системы. Удачи на собеседованиях и в реальных проектах!

#low-level design#объектно-ориентированное проектирование#классы#наследование#композиция
Al
Редакция Algolit

Пишем про алгоритмы, подготовку к собеседованиям и карьеру в IT — так, чтобы было понятно и полезно.

Хочешь закрепить знания на практике?

Решай задачи на Algolit — интерактивная платформа для обучения

Начать бесплатно →