Паттерн Decorator — python

Описываем животных, травоядных, водоплавающих, летающих. Вместо того, что бы описывать каждый вид по отдельности, мы создадим основной(абстрактный) объект животного

from abc import ABC, abstractmethod

class Creature(ABC):
    @abstractmethod
    def feed(self):
        pass
    
    @abstractmethod
    def move(self):
        pass
    
    @abstractmethod
    def make_noise(self):
        pass
    
class Animal(Creature):
    def feed(self):
        print("I eat grass")
        
    def move(self):
        print("I walk forward")
    
    def make_noise(self):
        print("WOOO!")


# Абстрактный декоратор, от которого будут наследоваться все другие
        
class AbstractDecorator(Creature):
    def __init__(self, obj):
        self.obj = obj
        
    def feed(self):
        self.obj.feed()
    
    def move(self):
        self.obj.move()
    
    def make_noise(self):
        self.obj.make_noise()
        
class Swimming(AbstractDecorator):
    def move(self):
        print("I swim")
    
    def make_noise(self):
        print("...")
        
class Flying(AbstractDecorator):
    def move(self):
        print("I fly")
    
    def make_noise(self):
        print("QUAAA!")
        
class Predator(AbstractDecorator):
    def feed(self):
        print("I eat other animals")
        
class Fast(AbstractDecorator):
    def move(self):
        self.obj.move()
        print("Fast!")
animal = Animal()
animal.feed()
animal.move()
animal.make_noise()
print()

animal = Swimming(animal)
animal.feed()
animal.move()
animal.make_noise()
print()

animal = Predator(animal)
animal.feed()
animal.move()
animal.make_noise()
print()

animal = Fast(animal)
animal.feed()
animal.move()
animal.make_noise()
print()


animal = Fast(animal)
animal.feed()
animal.move()
animal.make_noise()
print()
I eat grass
I walk forward
WOOO!

I eat grass
I swim
...

I eat other animals
I swim
...

I eat other animals
I swim
Fast!
...

I eat other animals
I swim
Fast!
Fast!
...

Если попытаться объяснить этот пример коротко и своими словами, то получается что изначально мы создаем базовый класс животного.

animal = Animal()
animal.move() # I walk forward
animal.feed() # I eat grass

После чего мы можем накладывать на этот объект декораторы, которые изменят поведение базового животного, превратя его в хищника или водоплавающего

Делаем хищника из обычного\базового животного:

predator = Predator(animal)

теперь для объекта predator — доступны все методы базового животного, но метод feed переопределен так что хищник уже есть не траву.

predator.move() # I walk forward
predator.feed() # I eat other animals

Попробуем теперь сделать водоплавающего хищника из обычного хищника

swimming_predator = Swimming(predator)
swimming_predator.move() # I swim
swimming_predator.feed() # I eat other animals