Conteúdos da cadeira

Princípios SOLID

Os cinco princípios com sinais de violação em código Java e a refatoração de uma classe de jogo.

Markdown

Perguntar sobre esta página

ChatGPTClaudePerplexityGeminiCopiar e abrir

Envia o link e pede à IA para ler a página. No Gemini, cola a pergunta copiada.

Ver pergunta para copiar
Nesta página

SOLID são cinco princípios para desenhar classes que aguentam mudanças. Não são regras de sintaxe que o compilador verifica: são cheiros que aprendes a detetar. Cada princípio responde a uma forma típica de o código apodrecer, e todos pagam dividendos quando o projeto cresce nas seis semanas do integrador.

Os cinco princípios

S de Single Responsibility: uma classe tem uma razão para mudar. Uma classe Jogo que lê input, atualiza monstros, desenha o ecrã e guarda recordes tem quatro razões para mudar, logo quatro fontes de bugs.

O de Open/Closed: aberta a extensão, fechada a modificação. Para adicionar um monstro novo, deves criar uma classe nova, não editar a antiga. A composição da página anterior é a técnica que torna isto possível: o Monstro aceita qualquer Comportamento sem ser modificado.

L de Liskov Substitution: uma subclasse deve poder substituir a classe mãe sem partir nada. Se Retangulo tem setLargura e setAltura independentes, um Quadrado que herda dele e força os lados iguais viola o princípio: código que funcionava com retângulos parte-se com quadrados. Quando a herança mente sobre a relação, troca por composição.

I de Interface Segregation: interfaces pequenas e específicas em vez de uma interface gorda. Uma interface Entidade que obriga paredes e itens a implementar mover está errada: separa em Desenhavel, Movivel e Coletavel, e cada classe implementa só o que usa.

D de Dependency Inversion: depender de abstrações, não de concretizações. O Monstro da página anterior recebe um Comportamento (interface), não um AndarEmZigZag concreto. Isto também é o que permite testar com doubles, como vais ver nos testes.

Exemplo: refatorar uma classe que faz tudo

Parte deste ControladorArena que viola Single Responsibility e Open/Closed:

public class ControladorArena {
    public void passo(String tecla) {
        if (tecla.equals("cima")) heroi.subir();
        else if (tecla.equals("baixo")) heroi.descer();
        // ... mais teclas, desenho do ecrã e lógica de monstros aqui
    }
}

Cada tecla nova, cada monstro novo e cada mudança no desenho mexem nesta classe. A refatoração separa as responsabilidades:

public class ControladorArena {
    private final Heroi heroi;
    private final Map<String, Comando> comandos;

    public void passo(String tecla) {
        comandos.getOrDefault(tecla, Comando.nada()).executar(heroi);
    }
}

Agora cada tecla é um objeto Comando registado no mapa. Adicionar uma tecla é criar uma classe e registá-la: extensão sem modificação (Open/Closed), e a classe voltou a ter uma só razão para mudar (Single Responsibility). O desenho do ecrã e a lógica dos monstros saem para as suas próprias classes pelo mesmo processo.

Ver o ficheiro no GitHub

À tua maneira

Escolhe como preferes ler.

Aparência
Ajustar cores e largura
Cor de destaque do tema FEUP
Tipo de letra

Álgebra, lógica e uma ideia de cada vez.

As tuas escolhas ficam guardadas neste navegador.

Pesquisar

Escreve para pesquisar em todo o site.

para escolher · Enter para abrir · Esc para fechar

Atalhos de teclado

Clica numa tecla para a mudar. Esc cancela. Backspace desativa.

PesquisarCtrl / Cmd K

Os atalhos não interferem enquanto escreves. Tab e Enter funcionam sempre.