Toda classe na UML é uma caixa dividida em três faixas, de cima pra baixo: o nome da classe no topo, os atributos no meio e os métodos na base. A visibilidade aparece no começo de cada linha (+ - #), e o tipo vem depois dos dois-pontos.
Caixa UML e classe Python são a mesma coisa em formatos diferentes: uma é desenho, a outra é código.
Para escolher entre composição e agregação, faça a pergunta: "se o todo for destruído, a parte some junto?". Some junto → composição ◆. Continua existindo → agregação ◇.
Toda relação é uma frase. Se você consegue ler o diagrama em voz alta, você entendeu o sistema.
Pra ler um diagrama, comece pelas caixas (as classes), depois siga as setas uma a uma, traduzindo cada relação numa frase. A multiplicidade nas pontas diz quantos objetos de cada lado participam.
Pessoa <|-- Aluno "Aluno é um Pessoa"
Turma "1" -- "*" Aluno "uma Turma tem vários Alunos"
Turma o-- Professor "a Turma usa um Professor" Já sabemos escrever classes, herança e composição. Hoje aprendemos a DESENHAR isso: o diagrama de classes da UML, a notação de visibilidade e relações, e como traduzir cada seta direto pra código Python.
roteiro da aula
A linguagem visual padrão pra modelar sistemas orientados a objetos — independente de linguagem.
Os três compartimentos (nome, atributos, métodos) e a visibilidade +/-/#.
As setas: herança, composição, agregação e associação — cada uma é uma frase.
Traduzir o diagrama pra classes Python: o ciclo modelar → codar.
ponte com as aulas anteriores
self.alunos = []). Na UML isso vira a multiplicidade *: "1 Turma tem * Alunos" — as listas da 18 são as associações 1→* do diagrama. o problema
definição
panorama
| item | detalhe |
|---|---|
| Diagrama de classes ⭐ | Mostra as classes, seus atributos/métodos e as relações entre elas. É o nosso foco de hoje. |
| Diagrama de sequência | Mostra a ordem das mensagens trocadas entre objetos ao longo do tempo. (Só citado.) |
| Diagrama de casos de uso | Mostra o que cada tipo de usuário pode fazer no sistema. (Só citado.) |
| Diagrama de estados | Mostra os estados pelos quais um objeto passa (ex.: pedido: criado → pago → enviado). (Só citado.) |
a caixa de classe
Toda classe na UML é uma caixa dividida em três faixas: o nome no topo, os atributos no meio, os métodos embaixo.
a caixa de classe
A caixa do slide anterior vira código quase 1 pra 1: o nome vira class, os atributos viram self.algo, os métodos viram def.
class Aluno:
def __init__(self, nome, matricula, cpf):
self.nome = nome # + público
self.matricula = matricula # + público
self.__cpf = cpf # - privado (dois underscores)
def matricular(self, turma):
print(f"{self.nome} entrou na turma {turma}")
def media(self):
return 0.0
aluno = Aluno("Ana", "2024001", "111.222.333-44")
print(aluno.nome) # Ana
print(aluno.matricula) # 2024001
aluno.matricular("INFO-1") # Ana entrou na turma INFO-1
print(aluno.media()) # 0.0 a caixa de classe
| item | detalhe |
|---|---|
| + público | Qualquer um acessa de fora. No Python: atributo/método normal, sem underscore (self.nome). |
| - privado | Só a própria classe acessa. No Python: dois underscores no início (self.__cpf). Aula 04. |
| # protegido | A classe e suas filhas acessam. No Python: um underscore (self._saldo) — convenção. Aula 04. |
a caixa de classe
Os mesmos três níveis, lado a lado: o símbolo na caixa UML e o que ele vira em Python (a convenção de underscores da aula 04).
+----------------------+
| ContaBancaria |
+----------------------+
| + titular: str |
| # saldo: float |
| - senha: str |
+----------------------+ class ContaBancaria:
def __init__(self, titular, senha):
self.titular = titular # + público
self._saldo = 0.0 # # protegido
self.__senha = senha # - privado a caixa de classe
A UML também anota o TIPO de cada atributo (depois do :) e os parâmetros e o retorno de cada método.
as relações
as relações
O triângulo vazio aponta pro PAI. A frase é sempre "É UM": Aluno é um Pessoa, Professor é um Pessoa.
as relações
O triângulo △ da UML vira (Pai) no Python. O super().__init__() reaproveita o construtor do pai.
class Pessoa:
def __init__(self, nome, cpf):
self.nome = nome
self.__cpf = cpf
def __str__(self):
return f"Pessoa: {self.nome}"
# herança: o triângulo △ da UML vira (Pessoa) no Python
class Aluno(Pessoa):
def __init__(self, nome, cpf, matricula):
super().__init__(nome, cpf) # reaproveita o __init__ do pai
self.matricula = matricula
def __str__(self):
return f"Aluno: {self.nome} (mat. {self.matricula})"
ana = Aluno("Ana", "111.222.333-44", "2024001")
print(ana) # Aluno: Ana (mat. 2024001)
print(isinstance(ana, Pessoa)) # True (Aluno É UM Pessoa) as relações
Losango CHEIO no lado do TODO. A frase é "CONTÉM": o todo cria a parte, e a parte morre junto com ele.
as relações
Losango VAZIO no lado do todo. A frase é "USA": o todo recebe a parte pronta, e ela vive independente.
as relações · a confusão clássica
As duas são "TEM UM". O que muda é o ciclo de vida da parte: a composição cria a parte, a agregação só usa uma que já existe.
class Pedido:
def __init__(self, numero):
self.numero = numero
# CRIA a parte dentro de si
self.itens = []
# sem o Pedido, os itens não existem.
# losango CHEIO. class Turma:
def __init__(self, professor):
# RECEBE a parte já pronta
self.professor = professor
# o professor existe sem a turma.
# losango VAZIO. as relações
Uma linha simples liga classes que se conhecem. Os números nas pontas (a multiplicidade) dizem QUANTOS de cada lado.
as relações
Uma classe abstrata (ABC, aula 10) aparece com o estereótipo «abstract» e, na tradição, o nome em itálico.
lendo o todo
Juntando tudo: herança (△), associação com multiplicidade (1/*) e agregação (◇) num diagrama só.
lendo o todo
na prática
na prática
No PlantUML, o diagrama inteiro é texto entre @startuml e @enduml. Cada relação tem um símbolo de seta.
@startuml
skinparam classAttributeIconSize 0
class Pessoa {
+ nome: str
- cpf: str
}
class Aluno {
+ matricula: str
}
class Professor {
+ salario: float
}
class Turma {
+ codigo: str
}
Aluno --|> Pessoa
Professor --|> Pessoa
Turma o-- Professor
Turma "1" -- "*" Aluno
@enduml --|> é herança (a ponta |> é o triângulo), o-- é agregação (o losango vazio), e -- é associação. A linha skinparam classAttributeIconSize 0 faz aparecer os símbolos + - # nos atributos (em vez das bolinhas coloridas), igual aos slides. O texto vira imagem automaticamente — sem arrastar caixa nenhuma.ao vivo · vamos construir juntos
Partindo do diagrama do próximo slide, a gente implementa juntos. Sistema: um Carro que É UM Veiculo (herança) e que CONTÉM um Motor (composição). Acompanhem a tradução de cada seta pra código.
Veiculo é a base. Carro ──△ Veiculo (herança, triângulo apontando pro pai). Carro ◆── Motor (composição, losango cheio: o carro cria o motor).
Com potencia e um __str__ que devolva algo como Motor 75cv. É a peça que o carro vai conter.
Veiculo guarda a marca; Carro herda dele com class Carro(Veiculo) e chama super().__init__(marca) no construtor.
No __init__ do Carro, crie o motor com self.motor = Motor(potencia) — o carro CRIA o próprio motor. Feche com um __str__ que use o motor.
ao vivo · vamos construir juntos
Em vez de desenhar no quadro, partimos deste diagrama. Leia as duas setas — e nos próximos slides a gente traduz cada uma pra código.
resolução · passos 1 e 2
Começamos pelas classes que não dependem do carro: o Motor (a parte que ele vai conter) e o Veiculo (a base da herança).
Motor não sabe que existe um carro — é uma peça independente, com seu próprio __str__.Veiculo é a base: guarda o que todo veículo tem (a marca). O Carro vai herdar dela.# Motor é PARTE do Carro (composição ◆): o Carro cria o próprio motor
class Motor:
def __init__(self, potencia):
self.potencia = potencia
def __str__(self):
return f"Motor {self.potencia}cv"
class Veiculo:
def __init__(self, marca):
self.marca = marca resolução · passos 3 e 4
Agora o Carro: ele herda de Veiculo com super() e contém um Motor criado no próprio __init__.
super().__init__(marca) reaproveita o construtor do pai — o triângulo △ da UML virou isso.self.motor = Motor(potencia) cria o motor DENTRO do carro — o losango ◆ da composição virou isso.# Carro É UM Veiculo (herança △)
class Carro(Veiculo):
def __init__(self, marca, potencia):
super().__init__(marca) # herança: reaproveita o pai
self.motor = Motor(potencia) # composição: cria o motor dentro de si
def __str__(self):
return f"{self.marca} — {self.motor}"
carro = Carro("Fiat", 75)
print(carro)
print(isinstance(carro, Veiculo)) resolução · o código completo
As peças que montamos passo a passo, agora num arquivo só — é exatamente isto que você roda. Repare como herança e composição convivem no mesmo Carro.
class Carro(Veiculo) + super() é a herança △; self.motor = Motor(...) é a composição ◆ — as duas no mesmo __init__.# Motor é PARTE do Carro (composição ◆): o Carro cria o próprio motor
class Motor:
def __init__(self, potencia):
self.potencia = potencia
def __str__(self):
return f"Motor {self.potencia}cv"
class Veiculo:
def __init__(self, marca):
self.marca = marca
# Carro É UM Veiculo (herança △)
class Carro(Veiculo):
def __init__(self, marca, potencia):
super().__init__(marca) # herança: reaproveita o pai
self.motor = Motor(potencia) # composição: cria o motor dentro de si
def __str__(self):
return f"{self.marca} — {self.motor}"
carro = Carro("Fiat", 75)
print(carro)
print(isinstance(carro, Veiculo)) resolução · saída esperada
Rodando o carro.py, é isto que aparece no terminal:
print(carro) chamou o __str__ do Carro, que por dentro usou o __str__ do Motor — a composição aparecendo na saída.isinstance(carro, Veiculo) devolve True: confirma que o Carro É UM Veiculo (a herança).Fiat — Motor 75cv
True recapitulando
| item | detalhe |
|---|---|
| UML | Unified Modeling Language: linguagem visual padrão pra modelar sistemas orientados a objetos. |
| Diagrama de classes | Mostra classes (caixas), atributos, métodos e as relações entre elas. |
| Visibilidade + - # | Público (sem underscore) / privado (__) / protegido (_). Aula 04. |
| Generalização △ | Herança "é um": triângulo vazio apontando pro pai. Vira class Filho(Pai). Aula 07. |
| Composição ◆ / Agregação ◇ | Todo-parte: ◆ a parte some junto (criada dentro) / ◇ a parte vive sozinha (recebida pronta). Aula 05. |
| Associação e multiplicidade | Linha simples ligando classes; 1, * e 1..* dizem quantos de cada lado participam. |
exercícios
Quatro exercícios em três níveis, do desenho ao código e de volta ao desenho. Comece em sala; termine o que faltar em casa. Mire pelo menos um de cada nível.
Dada a classe ContaBancaria com titular (público), __saldo (privado) e os métodos depositar(valor) e sacar(valor), desenhe a caixa UML com os três compartimentos e a visibilidade correta: + titular: str, - saldo: float, + depositar(valor): None, + sacar(valor): None. Use uma ferramenta (draw.io ou PlantUML) e entregue em PDF. Foco: a caixa de classe + visibilidade.
Para cada par abaixo, desenhe o trecho de diagrama UML numa ferramenta (draw.io ou PlantUML): as duas caixas e a seta correta entre elas — triângulo △ pra herança, losango ◆ pra composição, losango ◇ pra agregação, no lado certo. Embaixo de cada um, escreva a relação e justifique em 1 frase ("é um" / "tem um e some junto" / "usa um que existe sozinho"). Entregue os quatro num único PDF. Os pares: (a) Smartphone e Telefone; (b) Livro e Página; (c) Playlist e Música; (d) Floresta e Árvore. Foco: traduzir cada relação na seta certa. Dica de ouro: na dúvida entre ◆ e ◇, pergunte "se o todo acabar, a parte some junto?".
Dado o diagrama: Funcionario (base) com + nome: str e + salario: float; Gerente ──△ Funcionario (herança) com + equipe: list; e Gerente ◆── Projeto (composição). Implemente as três classes em Python com __init__ e __str__, respeitando a herança (super().__init__) e a composição (o Projeto é criado dentro do Gerente). Inclua um bloco de teste que cria um gerente e imprime, e entregue o arquivo .py. Foco: ler o diagrama e traduzir cada seta pra código.
Escolha UM mini sistema: (a) Locadora de jogos, (b) Cafeteria ou (c) Clínica. Primeiro DESENHE o diagrama de classes numa ferramenta (draw.io ou PlantUML), com pelo menos 3 classes, 1 herança e 1 composição ou agregação, incluindo visibilidade e multiplicidade. Depois IMPLEMENTE em Python a partir do SEU diagrama, com __str__ em cada classe e um bloco de teste. Entregue o diagrama em PDF e o código no arquivo .py. Foco: o ciclo completo modelar → codar (preparação pro projeto final da aula 25).
Agora que sabemos modelar com UML, vamos aprender SOLUÇÕES prontas pra problemas que se repetem no design de software — os padrões de projeto.