Fundamentos de Padrões de Projeto
Os padrões de projeto representam um conjunto de melhores práticas e soluções consolidadas para problemas recorrentes na engenharia de software. Eles abordam desafios como reutilização de código, escalabilidade de sistemas e manutenção da legibilidade. Em Python, esses padrões são categorizados em criaiconais, estruturais e comportamentais, aproveitando as características dinâmicas e orientadas a objetos da linguagem.
1. Padrão de Fábrica (Factory)
O Padrão de Fábrica é um padrão criacional que centraliza a lógica de instanciação de objetos. Ele desacopla a criação de objetos do seu uso, permitindo que o sistema seja estendido com novas implementações sem alterar o código cliente.
class EmailNotification:
def send(self, message: str) -> None:
print(f"Enviando e-mail: {message}")
class SmsNotification:
def send(self, message: str) -> None:
print(f"Enviando SMS: {message}")
class NotificationFactory:
@staticmethod
def get_notifier(channel: str):
if channel == "email":
return EmailNotification()
elif channel == "sms":
return SmsNotification()
raise ValueError("Canal de notificação desconhecido")
notifier = NotificationFactory.get_notifier("email")
notifier.send("Bem-vindo ao sistema!")
2. Padrão Singleton
O Padrão Singleton garante que uma classe possua apenas uma instância durante o ciclo de vida da aplicação, fornecendo um ponto de acesso global. Em Python, uma abordagem robusta e pythonica para implementar este padrão é através do uso de metaclasses.
class SingletonMeta(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super().__call__(*args, **kwargs)
return cls._instances[cls]
class DatabaseConnection(metaclass=SingletonMeta):
def __init__(self):
self.connection = "Conexão ativa"
conn1 = DatabaseConnection()
conn2 = DatabaseConnection()
print(conn1 is conn2) # Saída: True
3. Padrão Adaptador (Adapter)
O Padrão Adaptador atua como uma ponte entre duas interfaces incompatíveis. Ele é classificado como um padrão estrutural e é frequentemente utilizado para integrar componentes legados ou bibliotecas de terceiros que não possuem a assinatura de método esperada pelo sistema atual.
class ModernPaymentProcessor:
def process_payment(self, amount: float) -> None:
print(f"Processando pagamento moderno de ${amount}")
class LegacyPaymentGateway:
def execute_card_transaction(self, value: float) -> None:
print(f"Executando transação legada de ${value}")
class PaymentAdapter(ModernPaymentProcessor):
def __init__(self, legacy_gateway: LegacyPaymentGateway):
self._legacy_gateway = legacy_gateway
def process_payment(self, amount: float) -> None:
self._legacy_gateway.execute_card_transaction(amount)
legacy_system = LegacyPaymentGateway()
adapter = PaymentAdapter(legacy_system)
adapter.process_payment(150.00)
4. Padrão Decorador (Decorator)
O Padrão Decorador permite a adição de novas funcionalidades a um objeto de forma dinâmica e transparente. Python possui suporte nativo a decoradores através da sintaxe com o símbolo @, o que facilita a modificação do comportamento de funções e métodos sem alterar sua estrutura original.
import time
from functools import wraps
def measure_execution_time(func):
@wraps(func)
def wrapper(*args, **kwargs):
start_time = time.perf_counter()
result = func(*args, **kwargs)
end_time = time.perf_counter()
print(f"Execução de '{func.__name__}' levou {end_time - start_time:.4f} segundos")
return result
return wrapper
@measure_execution_time
def heavy_computation():
time.sleep(1)
return "Cálculo concluído"
heavy_computation()
5. Padrão Observador (Observer)
O Padrão Obesrvador estabelece uma relação de dependência um-para-muitos entre objetos. Quando o estado do objeto principle (sujeito) é alterado, todos os seus dependentes (observadores) são notificados automaticamente. Este padrão é a base para arquiteturas orientadas a eventos e sistemas de publicação/assinatura.
class NewsAgency:
def __init__(self):
self._subscribers = []
self._latest_news = ""
def subscribe(self, subscriber):
self._subscribers.append(subscriber)
def unsubscribe(self, subscriber):
self._subscribers.remove(subscriber)
def publish_news(self, news: str):
self._latest_news = news
self._notify_subscribers()
def _notify_subscribers(self):
for subscriber in self._subscribers:
subscriber.receive_update(self._latest_news)
class NewsSubscriber:
def receive_update(self, news: str):
pass
class MobileUser(NewsSubscriber):
def receive_update(self, news: str):
print(f"Notificação no celular: {news}")
agency = NewsAgency()
mobile_client = MobileUser()
agency.subscribe(mobile_client)
agency.publish_news("Python 3.12 lançado!")