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
 
cajuuh profile image
Pedro Alcântara

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

Collapse
 
luiz_felipe profile image
Luiz Felipe

Muito bom! 👏

Collapse
 
vitorrios1001 profile image
Vitor Rios

Obrigado Luiz 😊

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.