O Decorator é um padrão estrutural que permite adicionar novos comportamentos a objetos dinamicamente, colocando-os dentro de objetos wrapper especiais. O Decorator fornece uma alternativa flexível à herança para estender funcionalidades.
- Quando você precisa adicionar responsabilidades a objetos dinamicamente e de forma transparente
- Quando a herança não é viável porque você teria muitas subclasses diferentes
- Quando você precisa estender o comportamento de um objeto em tempo de execução
- Quando você quer adicionar ou remover responsabilidades de um objeto
from abc import ABC, abstractmethod
# Componente base
class Cafe(ABC):
@abstractmethod
def get_custo(self) -> float:
pass
@abstractmethod
def get_descricao(self) -> str:
pass
# Componente concreto
class CafeSimples(Cafe):
def get_custo(self) -> float:
return 5.0
def get_descricao(self) -> str:
return "Café simples"
# Decorator base
class DecoradorCafe(Cafe):
def __init__(self, cafe: Cafe):
self._cafe = cafe
def get_custo(self) -> float:
return self._cafe.get_custo()
def get_descricao(self) -> str:
return self._cafe.get_descricao()
# Decoradores concretos
class ComLeite(DecoradorCafe):
def get_custo(self) -> float:
return self._cafe.get_custo() + 2.0
def get_descricao(self) -> str:
return f"{self._cafe.get_descricao()}, com leite"
class ComChocolate(DecoradorCafe):
def get_custo(self) -> float:
return self._cafe.get_custo() + 3.0
def get_descricao(self) -> str:
return f"{self._cafe.get_descricao()}, com chocolate"
class ComCanela(DecoradorCafe):
def get_custo(self) -> float:
return self._cafe.get_custo() + 1.0
def get_descricao(self) -> str:
return f"{self._cafe.get_descricao()}, com canela"
# Exemplo de uso
def main():
# Café simples
cafe = CafeSimples()
print(f"Pedido: {cafe.get_descricao()}")
print(f"Custo: R$ {cafe.get_custo():.2f}\n")
# Café com leite
cafe_com_leite = ComLeite(CafeSimples())
print(f"Pedido: {cafe_com_leite.get_descricao()}")
print(f"Custo: R$ {cafe_com_leite.get_custo():.2f}\n")
# Café com leite e chocolate
cafe_especial = ComChocolate(ComLeite(CafeSimples()))
print(f"Pedido: {cafe_especial.get_descricao()}")
print(f"Custo: R$ {cafe_especial.get_custo():.2f}\n")
# Café com tudo
cafe_completo = ComCanela(ComChocolate(ComLeite(CafeSimples())))
print(f"Pedido: {cafe_completo.get_descricao()}")
print(f"Custo: R$ {cafe_completo.get_custo():.2f}")
if __name__ == "__main__":
main()- Maior flexibilidade que herança estática
- Permite adicionar ou remover responsabilidades em tempo de execução
- Princípio de Responsabilidade Única: divide a funcionalidade em classes
- Evita classes sobrecarregadas com funcionalidades em uma hierarquia de herança
- É difícil remover um wrapper específico da pilha de wrappers
- A ordem dos decoradores pode ser importante e difícil de controlar
- O código inicial de configuração dos decoradores pode ficar feio
- Pode resultar em muitas classes pequenas similares
- Mantenha a interface do componente simples para facilitar a decoração
- Certifique-se que os decoradores possam ser aplicados em qualquer ordem
- Considere criar decoradores que possam agregar múltiplos comportamentos
- Pense sobre a necessidade de desfazer ou remover decorações
- Use factories ou builders para simplificar a criação de objetos decorados