💻 Exemplos: Capítulo 05: Programação Orientada a Objetos: Classes, Métodos, Encapsulamento e @property
Especialização em Sistemas com Python 3.12+ • Capítulo 05
🎯 Demonstração Prática: Gestão de Contas Corporativas com Slots, Properties e Factory Methods
O exemplo abaixo demonstra a modelagem orientada a objetos de alta performance e encapsulamento estrito:
- Utilização de
__slots__para otimização de memória em nível de PVM. - Propriedades com validação defensiva através de
@propertye setters de invariantes. - Método de fábrica polimórfico
@classmethodcomtyping.Self(PEP 673). - Validador algorítmico utilitário com
@staticmethod. - Métodos dunder de representação formal
__repr__e legível__str__.
"""
demonstracao_poo_encapsulamento.py
Conta Bancária Corporativa de Alta Performance com Slots, Property e Factory Methods.
Compatível com Python 3.12+ (PEP 673 typing.Self e Type Hints Estritos).
"""
from __future__ import annotations
from decimal import Decimal, ROUND_HALF_EVEN
import json
import re
from typing import Final, Self
# ==============================================================================
# MODELO DE DOMÍNIO COM ENCAPSULAMENTO E SLOTS
# ==============================================================================
class ContaEmpresarial:
"""
Modela uma conta corporativa com slots estáticos para redução de pegada na Heap.
Não aloca __dict__ por instância.
"""
__slots__ = ("_numero_conta", "_razao_social", "_saldo", "_limite_cheque_especial", "_ativa")
def __init__(
self,
numero_conta: str,
razao_social: str,
saldo_inicial: Decimal = Decimal("0.00"),
limite_credito: Decimal = Decimal("5000.00")
) -> None:
if not self.validar_formato_conta(numero_conta):
raise ValueError(f"Formato de conta inválido: '{numero_conta}'. Padrão esperado: 'XXXXX-X'.")
self._numero_conta: str = numero_conta
self._razao_social: str = razao_social.strip()
self._saldo: Decimal = Decimal("0.00")
self._limite_cheque_especial: Decimal = Decimal("0.00")
self._ativa: bool = True
# Atribuição passando pelos setters para garantir invariantes
self.limite_cheque_especial = limite_credito
if saldo_inicial > Decimal("0.00"):
self.depositar(saldo_inicial)
# --------------------------------------------------------------------------
# PROPRIEDADES E ENCAPSULAMENTO
# --------------------------------------------------------------------------
@property
def numero_conta(self) -> str:
"""Acesso somente-leitura ao identificador da conta."""
return self._numero_conta
@property
def razao_social(self) -> str:
return self._razao_social
@property
def saldo(self) -> Decimal:
return self._saldo
@property
def saldo_total_disponivel(self) -> Decimal:
"""Propriedade computada somando saldo em conta e limite de crédito aprovado."""
return self._saldo + self._limite_cheque_especial
@property
def limite_cheque_especial(self) -> Decimal:
return self._limite_cheque_especial
@limite_cheque_especial.setter
def limite_cheque_especial(self, novo_limite: Decimal) -> None:
"""Setter defensivo com validação de limite mínimo."""
if novo_limite < Decimal("0.00"):
raise ValueError(f"O limite de crédito não pode ser negativo: {novo_limite}")
self._limite_cheque_especial = novo_limite.quantize(Decimal("0.01"), ROUND_HALF_EVEN)
@property
def ativa(self) -> bool:
return self._ativa
# --------------------------------------------------------------------------
# COMPORTAMENTOS TRANSACIONAIS
# --------------------------------------------------------------------------
def depositar(self, valor: Decimal) -> None:
"""Realiza crédito em conta com validação de valor estritamente positivo."""
if not self._ativa:
raise RuntimeError("Operação rejeitada: Conta bancária inativa.")
if valor <= Decimal("0.00"):
raise ValueError(f"Valor de depósito deve ser positivo: {valor}")
self._saldo = (self._saldo + valor).quantize(Decimal("0.01"), ROUND_HALF_EVEN)
def sacar(self, valor: Decimal) -> bool:
"""Efetua débito verificando disponibilidade total (saldo + limite)."""
if not self._ativa:
raise RuntimeError("Operação rejeitada: Conta bancária inativa.")
if valor <= Decimal("0.00"):
raise ValueError(f"Valor de saque deve ser positivo: {valor}")
if valor > self.saldo_total_disponivel:
return False # Fundos insuficientes
self._saldo = (self._saldo - valor).quantize(Decimal("0.01"), ROUND_HALF_EVEN)
return True
# --------------------------------------------------------------------------
# MÉTODOS DE FÁBRICA (@classmethod) E UTILITÁRIOS (@staticmethod)
# --------------------------------------------------------------------------
@classmethod
def from_json(cls, json_str: str) -> Self:
"""Factory Method polimórfico utilizando typing.Self para criar instâncias via JSON."""
dados = json.loads(json_str)
return cls(
numero_conta=str(dados["numero_conta"]),
razao_social=str(dados["razao_social"]),
saldo_inicial=Decimal(str(dados.get("saldo", "0.00"))),
limite_credito=Decimal(str(dados.get("limite", "5000.00")))
)
@staticmethod
def validar_formato_conta(numero: str) -> bool:
"""Valida se o identificador segue a máscara de 5 dígitos + hífen + 1 dígito verificador."""
return bool(re.match(r"^\d{5}-\d{1}$", numero.strip()))
# --------------------------------------------------------------------------
# DUNDER METHODS DE REPRESENTAÇÃO
# --------------------------------------------------------------------------
def __repr__(self) -> str:
return (
f"ContaEmpresarial(numero_conta='{self._numero_conta}', "
f"razao_social='{self._razao_social}', saldo={self._saldo}, "
f"limite={self._limite_cheque_especial})"
)
def __str__(self) -> str:
return f"Conta {self._numero_conta} - {self._razao_social} | Saldo: R$ {self._saldo:,.2f}"
# ==============================================================================
# EXECUÇÃO E TESTES
# ==============================================================================
if __name__ == "__main__":
payload_integracao = """
{
"numero_conta": "98124-7",
"razao_social": "TechCorp Inovacoes Digitais Ltda",
"saldo": "14500.50",
"limite": "20000.00"
}
"""
print("=" * 75)
print(" SISTEMA BANCÁRIO ORIENTADO A OBJETOS COM __SLOTS__")
print("=" * 75)
conta_pj: ContaEmpresarial = ContaEmpresarial.from_json(payload_integracao)
print(f"Instância Criada : {conta_pj}")
print(f"Representação : {repr(conta_pj)}")
print(f"Saldo Próprio : R$ {conta_pj.saldo:>12.2f}")
print(f"Limite Aprovado : R$ {conta_pj.limite_cheque_especial:>12.2f}")
print(f"Poder de Compra : R$ {conta_pj.saldo_total_disponivel:>12.2f}")
print("-" * 75)
print(">> Realizando saque de R$ 25.000,00 (Entrando no limite de crédito)...")
sucesso_saque = conta_pj.sacar(Decimal("25000.00"))
print(f"Saque Aprovado? : {sucesso_saque}")
print(f"Novo Saldo : R$ {conta_pj.saldo:>12.2f} (Utilizando cheque especial)")
print(f"Disponível Rest. : R$ {conta_pj.saldo_total_disponivel:>12.2f}")
print("-" * 75)
print(">> Tentativa de saque de R$ 15.000,00 (Estouro de limite)...")
sucesso_estouro = conta_pj.sacar(Decimal("15000.00"))
print(f"Saque Aprovado? : {sucesso_estouro} (Rejeitado por fundos insuficientes)")
print("=" * 75)