Ну чтож... #жарим_код!
RPG в консоли — это база. Код выполняет свою задачу, но написан так, что любая попытка его масштабировать вызовет БООООООООЛЬ. Разберем самые важные проблемы 👇
1️⃣ Ctrl+C, Ctrl+V наследование
Смотрим на иерархию брони:
class Armor(Item):
def __init__(self, name, category, strength=None, value_strength=None...): # и еще 100500 аргументов
super().__init__(name, category)
# ...
class Helmet(Armor):
def __init__(self, ...):
super().__init__(...)
class Chestplate(Armor):
# Копия Helmet
class Greaves(Armor):
# Копия ChestplateВсе эти классы (
Helmet, Chestplate, Greaves, Boots) — абсолютно идентичны. Они не добавляют ни новых атрибутов, ни нового поведения. Они не делают ничего, кроме вызова super().__init__. ООП создано не для того, чтобы описывать каждый физический предмет в мире отдельным классом. Если сущности отличаются только названием категории — это должен быть один класс
Armor, у которого есть атрибут slot_type (в идеале через Enum). 2️⃣ Конструктор Франкенштейна
Посмотрите, как создается предмет:
crown = Helmet('Шлем Господства', 'Шлем', 'Сила', 5, 'Ловкость', 7, 'Интеллект', 3)Никогда не хардкодьте названия статов в сигнатуру метода. Используйте словари.
Вместо этой простыни параметров, предмет должен принимать
stats={'strength': 5, 'agility': 7, 'intellect': 3}.3️⃣ Инцест классов
Класс
Characteristic принимает в себя hero, а потом делает вот это:for item in self._hero.slots_equipment.values():
if item:
if hasattr(item, 'value_strength') and item.value_strength:
self.attributes['strength'] += item.value_strengthЭто называется "Tight Coupling" (жесткая связность). Класс характеристик лезет грязными руками в инвентарь героя, проверяет, есть ли там предметы, а потом через
hasattr (что само по себе костыль в 99% случаев) пытается вытащить из них статы. Герой должен сам опрашивать свою экипировку и передавать итоговые модификаторы в систему характеристик. А сейчас хвост виляет собакой.
4️⃣ Использование Exceptions для логики
В методе
equip_armor видим такое:try:
if key not in self.slots_equipment:
print('Нет такого слота.')
# ... логика ...
except KeyError:
print(f'Предмет не найден')Во-первых, перехват широкого
KeyError замаскирует вам реальные баги в коде (например, опечатку в словаре внутри try). Во-вторых, исключения — для исключительных ситуаций, а не для проверки наличия предмета в инвентаре. Для этого есть метод словаря .get().В общем, для начала вместо 10 бесполезных классов брони и монструозных конструкторов можно сделать хотя бы так:
from dataclasses import dataclass
from enum import Enum
class EquipmentSlot(Enum):
HEAD = "Шлем"
CHEST = "Нагрудник"
WEAPON = "Оружие"
@dataclass
class Equipment:
name: str
slot: EquipmentSlot
stats_bonus: dict[str, int]
# Создание предмета:
crown = Equipment(
name='Шлем Господства',
slot=EquipmentSlot.HEAD,
stats_bonus={'strength': 5, 'agility': 7, 'intellect': 3}
)И всё. Никаких дублей кода, защита от опечаток в слотах через Enum, и расширяемая система статов, куда можно завтра добавить хоть "Удачу", не переписывая
__init__ у десятка классов.ООП — это не когда у вас на каждую сущность во вселенной заведен отдельный класс. ООП — это про управление сложностью и состоянием.
Но для одного месяца обучения — это абсолютно нормальный этап эволюции.
📖 Читаем:
- Когда класс в Python — это зло: 6 случаев, когда вы усложняете себе жизнь
- Принципы SOLID в ООП с примерами на Python
Комментарии
0Комментариев пока нет.
Войдите, чтобы участвовать в обсуждении.