Слайд 4: Абстрактные классы и множественное наследование

Теория: Абстрактные классы

Абстрактные классы определяют общий интерфейс для группы связанных классов, при этом некоторые методы могут не иметь реализации.

1. Абстрактные классы с ABC:

from abc import ABC, abstractmethod

class ElementalReaction(ABC):
    """Абстрактный класс элементальной реакции"""
    
    @abstractmethod
    def apply(self, base_damage: float) -> float:
        """Применить реакцию к базовому урону"""
        pass
    
    @abstractmethod
    def get_duration(self) -> float:
        """Получить длительность эффекта"""
        pass

class Vaporize(ElementalReaction):
    """Конкретная реализация реакции Пар"""
    
    def apply(self, base_damage: float) -> float:
        return base_damage * 1.5  # Пиро по Гидро
        
    def get_duration(self) -> float:
        return 0  # Мгновенная реакция

2. Множественное наследование:

class StatusEffect(ABC):
    """Абстрактный класс эффекта состояния"""
    
    @abstractmethod
    def apply_effect(self, target: 'Character') -> None:
        pass

class DamageOverTime(StatusEffect):
    def apply_effect(self, target: 'Character') -> None:
        damage = self.calculate_dot_damage()
        target.take_damage(damage)

class HealingEffect(StatusEffect):
    def apply_effect(self, target: 'Character') -> None:
        healing = self.calculate_healing()
        target.heal(healing)

class BurningStatus(DamageOverTime, ElementalReaction):
    """Эффект горения: и урон по времени, и элементальная реакция"""
    
    def apply(self, base_damage: float) -> float:
        dot_damage = base_damage * 0.25
        return dot_damage
        
    def get_duration(self) -> float:
        return 12  # Длится 12 секунд

3. Миксины (примеси):

class ElementalMixin:
    """Миксин для элементальных способностей"""
    
    def apply_element(self, element: str) -> None:
        self.current_element = element
        self.element_duration = 10

class ShieldMixin:
    """Миксин для щитов"""
    
    def create_shield(self, base_value: float) -> None:
        self.shield_hp = base_value
        self.shield_active = True

class Diona(Character, ElementalMixin, ShieldMixin):
    """Персонаж, использующий элементы и щиты"""
    
    def elemental_skill(self):
        self.apply_element("Крио")
        self.create_shield(1234.5)

4. Порядок разрешения методов (MRO):

class A:
    def method(self):
        return "A"

class B(A):
    def method(self):
        return "B" + super().method()

class C(A):
    def method(self):
        return "C" + super().method()

class D(B, C):
    pass

# Порядок поиска методов:
print(D.mro())  # [D, B, C, A, object]
d = D()
print(d.method())  # "BCA"

Важно помнить:

  • Абстрактные методы должны быть реализованы в дочерних классах
  • Нельзя создать экземпляр абстрактного класса
  • При множественном наследовании методы ищутся слева направо
  • super() использует MRO для поиска следующего метода
  • Миксины обычно содержат дополнительную функциональность без состояния

Задача: Система элементальных реакций

Создайте систему классов для элементальных реакций Genshin Impact:

Подсказка: Пример структуры классов:

class ElementalReaction(ABC):
    @abstractmethod
    def apply(self, character: 'Character', 
             target: 'Character') -> float:
        """Применить реакцию"""
        
class Vaporize(AmplifyingReaction, ElementalGaugeMixin):
    def get_multiplier(self, trigger_element: str) -> float:
        """Получить множитель усиления"""
        
class Swirl(TransformativeReaction, DurationMixin):
    def spread_element(self, element: str, em: int) -> None:
        """Распространить элемент по области"""