DEV Community

Cover image for SOLID: Princípios para um Design de Software Eficaz
Vitor Rios
Vitor Rios

Posted on

SOLID: Princípios para um Design de Software Eficaz

No mundo do desenvolvimento de software, a qualidade e a sustentabilidade do design são cruciais. Aqui, os princípios SOLID desempenham um papel fundamental. Desenvolvidos por Robert C. Martin, esses princípios orientam os desenvolvedores na criação de software que é fácil de manter, escalar e compreender. Vamos explorar cada um deles com exemplos práticos em TypeScript.

1. Single Responsibility Principle (Princípio da Responsabilidade Única)

Conceito: Uma classe deve ter apenas uma razão para mudar, significando que deve ter apenas uma tarefa ou responsabilidade.

Exemplos:

// Ruim: a classe lida com detalhes de usuário e log
class User {
    private name: string;

    constructor(name: string) {
        this.name = name;
    }

    saveUser() {
        console.log('Usuário salvo no banco de dados');
    }

    logUserDetails() {
        console.log(`Usuário: ${this.name}`);
    }
}

// Bom: separar responsabilidades
class User {
    private name: string;

    constructor(name: string) {
        this.name = name;
    }

    saveUser() {
        console.log('Usuário salvo no banco de dados');
    }
}

class UserLogger {
    logUser(user: User) {
        console.log(`Usuário: ${user.getName()}`);
    }
}
Enter fullscreen mode Exit fullscreen mode

Explicação: Ao separar a lógica de log do usuário da sua classe User, seguimos o princípio da responsabilidade única. Isso torna as classes mais fáceis de entender, testar e manter.

2. Open/Closed Principle (Princípio Aberto/Fechado)

Conceito: Entidades de software (classes, módulos, funções) devem estar abertas para extensão, mas fechadas para modificação.

Exemplos:

// Ruim: a função de desenho deve ser modificada para cada nova forma
class Circle {}
class Square {}

function drawShape(shape: Circle | Square) {
    if (shape instanceof Circle) {
        // desenha círculo
    } else if (shape instanceof Square) {
        // desenha quadrado
    }
}

// Bom: usando polimorfismo
interface Shape {
    draw(): void;
}

class Circle implements Shape {
    draw() {
        // desenha círculo
    }
}

class Square implements Shape {
    draw() {
        // desenha quadrado
    }
}

function drawShape(shape: Shape) {
    shape.draw();
}
Enter fullscreen mode Exit fullscreen mode

Explicação: Este princípio é exemplificado permitindo que novas formas sejam adicionadas (extensão) sem alterar a função drawShape (modificação). Promove um design flexível e sustentável.

3. Liskov Substitution Principle (Princípio da Substituição de Liskov)

Conceito: Objetos de uma classe devem ser substituíveis por objetos de suas subclasses sem quebrar a aplicação.

Exemplo:

// Bom: substituição sem alterar o comportamento
class Bird {
    fly() {
        // implementação do voo
    }
}

class Duck extends Bird {}

function makeBirdFly(bird: Bird) {
    bird.fly();
}

const duck = new Duck();
makeBirdFly(duck); // Funciona corretamente
Enter fullscreen mode Exit fullscreen mode

Explicação: Este princípio garante que as subclasses mantenham o comportamento esperado das classes base, promovendo a reutilização e correção do código.

4. Interface Segregation Principle (Princípio da Segregação de Interface)

Conceito: Nenhuma classe deve ser forçada a implementar interfaces que não vai usar.

Exemplo:

// Ruim: interface muito grande
interface Worker {
    work(): void;
    eat(): void;
}

class HumanWorker implements Worker {
    work() { /*...*/ }
    eat() { /*...*/ }
}

class RobotWorker implements Worker {
    work() { /*...*/ }
    eat() { // Robôs não comem, mas a implementação é obrigatória
    }
}

// Bom: interfaces segregadas
interface Worker {
    work(): void;
}

interface Eater {
    eat(): void;
}

class HumanWorker implements Worker, Eater {
    work() { /*...*/ }
    eat() { /*...*/ }
}

class RobotWorker implements Worker {
    work() { /*...*/ }
}
Enter fullscreen mode Exit fullscreen mode

Explicação: Este princípio promove a criação de interfaces específicas e relevantes, evitando a implementação desnecessária de métodos, que pode levar a um código confuso e de difícil manutenção.

5. Dependency Inversion Principle (Princípio da Inversão de Dependência)

Conceito: Módulos de alto nível não devem depender de módulos de baixo nível. Ambos devem depender de abstrações.

Exemplo:

// Ruim: alto nível depende diretamente de baixo nível
class LightBulb {
    turnOn() { /*...*/ }
    turnOff() { /*...*/ }
}

class ElectricPowerSwitch {
    private bulb: LightBulb;

    constructor(bulb: LightBulb) {
        this.bulb = bulb;
    }

    operate() {
        if (this.bulb.isOn()) {
            this.bulb.turnOff();
        } else {
            this.bulb.turnOn();
        }
    }
}

// Bom: depende de abstrações
interface Switchable {
    turnOn(): void;
    turnOff(): void;
}

class LightBulb implements Switchable {
    turnOn() { /*...*/ }
    turnOff() { /*...*/ }
}

class ElectricPowerSwitch {
    private device: Switchable;

    constructor(device: Switchable) {
        this.device = device;
    }

    operate() {
        // ...
    }
}
Enter fullscreen mode Exit fullscreen mode

Explicação: Este princípio minimiza a dependência direta entre módulos de software, promovendo um acoplamento mais fraco e um design mais flexível.

Conclusão

Os princípios SOLID são fundamentais para qualquer desenvolvedor que busque criar aplicações robustas, sustentáveis e fáceis de manter. Ao aplicar ess

es princípios, o software se torna mais modular, o que facilita a realização de mudanças, a implementação de novas funcionalidades e a manutenção do sistema como um todo. Em TypeScript, esses princípios podem ser implementados de maneira clara e eficaz, contribuindo significativamente para a qualidade do design de software.

Top comments (4)

Collapse
 
luiz_felipe profile image
Luiz Felipe

Muito bom! 👏

Collapse
 
vitorrios1001 profile image
Vitor Rios

Obrigado Luiz 😊

Collapse
 
cajuuh profile image
Pedro Alcântara

sempre bom ter um resuminho de SOLID na mão, valeu meu querido

Collapse
 
gabrielvileladev profile image
Gabriel Marcos

Excelente explicação dos princípios SOLID, deixou de fato evidente a real necessidade de se utilizar cada um.