Skip to content

Latest commit

 

History

History
116 lines (86 loc) · 3.68 KB

File metadata and controls

116 lines (86 loc) · 3.68 KB

Decorator

O que é?

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 usar?

  • 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

Exemplo em Python

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()

Vantagens

  1. Maior flexibilidade que herança estática
  2. Permite adicionar ou remover responsabilidades em tempo de execução
  3. Princípio de Responsabilidade Única: divide a funcionalidade em classes
  4. Evita classes sobrecarregadas com funcionalidades em uma hierarquia de herança

Desvantagens

  1. É difícil remover um wrapper específico da pilha de wrappers
  2. A ordem dos decoradores pode ser importante e difícil de controlar
  3. O código inicial de configuração dos decoradores pode ficar feio
  4. Pode resultar em muitas classes pequenas similares

Considerações de Implementação

  • 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