Как спроектировать классы для простого файлообменника на Python

Ответ

Основной принцип при проектировании — разделение ответственности (Separation of Concerns). Каждый класс должен выполнять одну четкую задачу. Для файлообменника можно выделить три ключевые сущности:

  1. File: Модель данных, представляющая файл. Хранит метаданные и содержимое.
  2. User: Представляет пользователя системы, который может выполнять действия (загружать, скачивать).
  3. Storage: Сервисный класс, отвечающий за логику хранения, добавления и поиска файлов.

Пример реализации:

# 1. Модель данных
class File:
    def __init__(self, name: str, size: int, content: bytes):
        self.name = name
        self.size = size
        self.content = content

    def get_info(self) -> str:
        return f"File: {self.name}, Size: {self.size} bytes"

# 2. Хранилище
class Storage:
    def __init__(self):
        # В реальном приложении здесь была бы логика работы с БД или файловой системой
        self._files = {}

    def add_file(self, file: File):
        if file.name in self._files:
            raise ValueError(f"File with name {file.name} already exists.")
        self._files[file.name] = file
        print(f"File '{file.name}' added to storage.")

    def get_file(self, name: str) -> File | None:
        return self._files.get(name)

# 3. Пользователь
class User:
    def __init__(self, username: str):
        self.username = username

    def upload_file(self, file: File, storage: Storage):
        print(f"User '{self.username}' is uploading '{file.name}'...")
        storage.add_file(file)

### Взаимодействие классов:

# Создаем экземпляры
storage = Storage()
user = User("alice")
file_to_upload = File("document.txt", 1024, b"some binary data")

# Пользователь загружает файл в хранилище
user.upload_file(file_to_upload, storage)

# Другой пользователь или система может получить файл из хранилища
retrieved_file = storage.get_file("document.txt")
if retrieved_file:
    print(f"Successfully retrieved: {retrieved_file.get_info()}")

Почему такой подход эффективен:

  • Инкапсуляция: Логика хранения файлов скрыта внутри класса Storage.
  • Масштабируемость: Легко добавить новые функции, например, класс Permissions для управления доступом, не изменяя существующие классы.
  • Тестируемость: Каждый класс можно тестировать независимо друг от друга.

Ответ 18+ 🔞

Ну, слушай, смотри, блядь. Вот этот твой принцип проектирования — разделение ответственности. Это как если бы ты, сука, на кухне готовил: один режет, другой жарит, третий моет посуду. А не так, чтобы один мудак и резал, и жарил, и в итоге всё в говне, и посуда грязная, и пожар, блядь.

Вот смотри, для файлообменника нам надо три главных чувака:

  1. File — это просто кусок данных, как труп, блядь. Лежит себе, имя имеет, размер, содержимое. Ничего не делает, просто существует, пизда.
  2. User — это активный пидорас, который этот файл-трус куда-то тащит. Загружает, скачивает. Его задача — действовать.
  3. Storage — это, блядь, склад, архив, подвал. Его задача — принимать файлы, хранить их и по первому требованию выдавать, как стукач на допросе.

Вот смотри, как это выглядит в коде, сука:

# 1. Файл — просто модель, тупая структура
class File:
    def __init__(self, name: str, size: int, content: bytes):
        self.name = name
        self.size = size
        self.content = content

    def get_info(self) -> str:
        return f"File: {self.name}, Size: {self.size} bytes"

# 2. Хранилище — сервис, который всё организует
class Storage:
    def __init__(self):
        # В реальности тут была бы база данных или файловая система, а не словарь, но для примера сойдёт
        self._files = {}

    def add_file(self, file: File):
        if file.name in self._files:
            raise ValueError(f"File with name {file.name} already exists.")
        self._files[file.name] = file
        print(f"File '{file.name}' added to storage.")

    def get_file(self, name: str) -> File | None:
        return self._files.get(name)

# 3. Пользователь — активный участник процесса
class User:
    def __init__(self, username: str):
        self.username = username

    def upload_file(self, file: File, storage: Storage):
        print(f"User '{self.username}' is uploading '{file.name}'...")
        storage.add_file(file)

### А теперь, блядь, смотрим, как они взаимодействуют:

# Создаём участников этой драмы
storage = Storage()  # Склад
user = User("alice")  # Пользователь-активист
file_to_upload = File("document.txt", 1024, b"some binary data")  # Сам файл, наш "труп"

# Пользователь тащит файл на склад
user.upload_file(file_to_upload, storage)

# Потом кто-то другой может прийти и забрать этот файл со склада
retrieved_file = storage.get_file("document.txt")
if retrieved_file:
    print(f"Successfully retrieved: {retrieved_file.get_info()}")

А теперь, сука, почему это охуенно?

  • Инкапсуляция: Вся логика хранения спрятана внутри Storage. Пользователь не лезет в словарь _files и не портит там всё, как слон в посудной лавке. Он просто говорит: «На, храни». И всё.
  • Масштабируемость: Захотел добавить права доступа? Создай класс Permissions, блядь. Не надо переписывать Storage или User с нуля. Просто подключаешь нового участника в игру.
  • Тестируемость: Каждого из этих уродов можно тестировать по отдельности. Можешь тестировать Storage, не создавая пользователя. Можешь тестировать логику загрузки, не трогая реальное хранилище. Красота, ёпта!

Вот и весь принцип. Не делай из одного класса универсального солдата, который и швец, и жнец, и на дуде игрец. Это путь в ад, блядь. Разделяй, властвуй и не еби себе мозг.