SOLID para desenvolvedores iniciantes.
Published: 2024-01-23 17:46:40

Antes de mais nada, precisamos definir o que, afinal, é **SOLID** e por que ele é tão importante na **Programação Orientada a Objetos (POO)**?

Bem, **SOLID** é um acrônimo, ou seja, uma sigla na qual cada letra corresponde a um dos cinco princípios de design de código. Esses princípios são utilizados para facilitar a compreensão, o desenvolvimento e a manutenção de software, ou seja, o famoso _Clean Code_.

Acredito que a maioria de vocês já deve ter ouvido falar de **Robert C. Martin**, mais conhecido no mundo do desenvolvimento como _Uncle Bob_. 

A história da origem do **SOLID** começou no final da década de 1980, enquanto _Uncle Bob_ discutia os princípios de design de software com outros usuários de uma rede social chamada USENET, com o objetivo de catalogar os mais importantes. Essa catalogação durou bastante tempo, mas, como foi dito em sua obra “_Clean Architecture_” ou “Arquitetura Limpa”, Bob explica que, em 2004, seu amigo **Michael Fathers** enviou um e-mail dizendo que, se reorganizasse esses princípios tão importantes para o desenvolvimento, as primeiras letras formariam o que conhecemos como **SOLID** (sólido em português), e foi aí que nasceu o acrônimo.

Sem mais delongas, vou explicar o que cada letra significa e demonstrar um exemplo que faça sentido.

## Começamos com a letra S de **Single Responsiblity Principle** (Principio da responsabilidade única)

O primeiro princípio diz que uma classe deve ser especialista em apenas um assunto. Isto é, a classe precisa ter apenas uma função. Se mais de uma função for atribuída a ela, ou se estiver lidando com mais de uma responsabilidade, provavelmente o código precisa ser revisado, pois isso dificultará a realização de testes. Se o código estiver difícil de ser testado, então ele pode ser melhorado.

Vou usar de exemplo aqui o anime "One Punch Man", sabemos que o Saitama tem uma única responsabilidade, derrotar monstros com um unico soco. Ele não se envolve em outras tarefas como por exemplo, liderar uma equipe ou planejar estratégias 

codigo em c# para exemplificar:

```bash
using System;
public class Heroi
{
    public string Nome { get; private set; }
    public HeroiAnimeCombate(string nome)
    {
        Nome = nome;
    }
    public void DerrotarMonstroComUmSoco()
    {
        Console.WriteLine($"{Nome} derrota o monstro com um único soco!");
    }
}

class Program
{
    static void Main()
    {
        HeroiAnimeCombate saitama = new Heroi("Saitama");
        saitama.DerrotarMonstroComUmSoco();
    }
}
```

## O de **Open-Closed Principle** (Principio Aberto-fechado)

Esse principio diz que um objeto ou entidade deve estar aberto a extensões porém fechado a modificações, O que quer dizer isso ? aberto e fechado ? bom, isso significa que um objeto deve estar apto a receber novos comportamentos e recursos porem ele não deve sofrer alteração em seu codigo fonte.

por exemplo, dessa vez irei utilizar o mundo de "Naruto". O personagem Naruto é um otimo exemplo desse principio ja que ele é aberto para extensão, ou seja, consegue aprender muitos jutsus novos como rasengan e jutsu clone das sombras porem fechado para modificação pois em nenhum momento ele deixou de querer ser o hokage da vila. Seu objetivo continuou o mesmo.

codigo em c# para exemplificar:
```bash
using System;
using System.Collections.Generic;

public interface IJutsu
{
    void Executar();
}

public class Rasengan : IJutsu
{
    public void Executar()
    {
        Console.WriteLine("Executando Rasengan!");
    }
}

public class JutsuCloneSombras : IJutsu
{
    public void Executar()
    {
        Console.WriteLine("Executando Jutsu Clone das Sombras!");
    }
}

public class Ninja
{
    public string Nome { get; private set; }
    private List<IJutsu> jutsus;

    public Ninja(string nome)
    {
        Nome = nome;
        jutsus = new List<IJutsu>();
    }

    public void AprenderNovoJutsu(IJutsu novoJutsu)
    {
        jutsus.Add(novoJutsu);
    }

    public void ExecutarJutsus()
    {
        Console.WriteLine($"{Nome} está executando seus jutsus:");
        foreach (var jutsu in jutsus)
        {
            jutsu.Executar();
        }
    }
}

class Program
{
    static void Main()
    {
        Ninja naruto = new Ninja("Naruto");
        naruto.AprenderNovoJutsu(new Rasengan());
        naruto.AprenderNovoJutsu(new JutsuCloneSombras());

        naruto.ExecutarJutsus();
    }
}
```

## **L - Liskov Substitution Principle** (Princípio de substituição de Liskov)

O princípio de Liskov diz que uma classe derivada deve ser substituível por sua classe base, ou seja, basicamente, levando para a questão de herança em OO (Orientação a Objetos), a classe filha deve desempenhar as mesmas funções da classe pai.

Vamos usar como exemplo o anime "My Hero Academy", onde todos os estudantes da U.A. School podem ser substituídos numa luta contra vilões (obviamente, uns vão desempenhar melhor que outros, mas isso não vem ao caso), porque todos eles foram treinados para se tornarem heróis, ou seja, herdam da classe pai "Herói".

codigo em c# para exemplificar:
```bash
using System;

public class Heroi
{
    public string Nome { get; private set; }

    public Heroi(string nome)
    {
        Nome = nome;
    }

    public virtual void RealizarAcaoHeroica()
    {
        Console.WriteLine($"{Nome} está realizando uma ação heroica!");
    }
}

public class EstudanteUA : Heroi
{
    public EstudanteUA(string nome) : base(nome)
    {
    }

    public override void RealizarAcaoHeroica()
    {
        base.RealizarAcaoHeroica();
        Console.WriteLine($"{Nome} está usando seus poderes de estudante para complementar a ação heroica!");
    }
}

class Program
{
    static void Main()
    {
        Heroi heroi = new EstudanteUA("Midoriya");
        heroi.RealizarAcaoHeroica();
    }
}
```

## I - **Interface Segregation Principle** (Principio da segregação de interface)

O princípio de segregação de interface diz que uma classe não deve ser forçada a implementar interfaces e métodos que não irá utilizar.

Basicamente, esse princípio diz que criar interfaces mais específicas é melhor do que genéricas, pois nem todas as funções podem ser realizadas e isso causaria um trabalho a mais.

Como exemplo, posso citar ‘One Piece’, onde o bando do Chapéu de Palha é um exemplo do princípio de segregação de interface. Cada membro da tripulação tem habilidades e funções específicas e interage apenas com as partes de seu sistema (navio) que são relevantes para sua função.

Por exemplo, Sanji é o cozinheiro e sua principal interface é a cozinha. Ele não precisa saber navegar e nem lutar com espadas, pois isso é dever de Nami e Zoro, que seguem as devidas interfaces

codigo em c# para exemplificar:
```bash
using System;

public interface IHabilidadesEspecificas
{
    void RealizarHabilidadeEspecifica();
}

public class Sanji : IHabilidadesEspecificas
{
    public void RealizarHabilidadeEspecifica()
    {
        Console.WriteLine("Sanji está cozinhando!");
    }
}

public class Nami : IHabilidadesEspecificas
{
    public void RealizarHabilidadeEspecifica()
    {
        Console.WriteLine("Nami está navegando!");
    }
}

public class Zoro : IHabilidadesEspecificas
{
    public void RealizarHabilidadeEspecifica()
    {
        Console.WriteLine("Zoro está duelando!");
    }
}

public class TripulacaoChapeuDePalha
{
    private IHabilidadesEspecificas membroTripulacao;

    public void DefinirMembroDaTripulacao(IHabilidadesEspecificas membro)
    {
        membroTripulacao = membro;
    }

   
    public void RealizarAcaoTripulacao()
    {
        if (membroTripulacao != null)
            membroTripulacao.RealizarHabilidadeEspecifica();
        else
            Console.WriteLine("Sem membro definido na tripulação.");
    }
}

class Program
{
    static void Main()
    {
        TripulacaoChapeuDePalha tripulacao = new TripulacaoChapeuDePalha();

        tripulacao.DefinirMembroDaTripulacao(new Sanji());
        tripulacao.RealizarAcaoTripulacao();

        tripulacao.DefinirMembroDaTripulacao(new Nami());
        tripulacao.RealizarAcaoTripulacao();

        tripulacao.DefinirMembroDaTripulacao(new Zoro());
        tripulacao.RealizarAcaoTripulacao();
    }
}

```

## D - **Dependency Inversion Principle** (Principio da inversão da dependência)

O princípio de inversão de dependência afirma que módulos de alto nível devem depender de módulos de baixo nível por meio de abstrações, e não de implementações concretas.

Em outras palavras, o conceito diz que a classes de alto nível deve depender de interfaces ou classes abstratas, e não de classes concretas.

Um anime que faz bastante sentido ser usado como exemplo é FullMetal Alchemist. No anime, os irmãos Elric estão em busca da pedra filosofal, pra isso, eles precisam aprender alquimia avançada. Eles dependem da alquimia para atingir seus objetivos, mas não se importam com a implementação específica dela. Eles só precisam saber que a alquimia pode ajudá-los.

A alquimia é uma abstração que representa a capacidade de transmutar a matéria. A implementação pode variar, porém a abstração permanece a mesma.

codigo em c# para exemplificar:
```bash
using System;

// Abstração
public interface IAlquimia
{
    void Transmutar();
}

// Implementação
public class AlquimiaAvancada : IAlquimia
{
    public void Transmutar()
    {
        Console.WriteLine("Realizando transmutação avançada...");
    }
}

// Classe de alto nível dependendo da abstração
public class BuscaPedraFilosofal
{
    private readonly IAlquimia alquimia;

    public BuscaPedraFilosofal(IAlquimia alquimia)
    {
        this.alquimia = alquimia;
    }

    public void RealizarMissao()
    {
        Console.WriteLine("Iniciando missão para encontrar a pedra filosofal.");
        alquimia.Transmutar();
        Console.WriteLine("Missão concluída.");
    }
}

class Program
{
    static void Main()
    {
        //a classe de alto nível depende da abstração (IAlquimia), não da implementação concreta
        IAlquimia alquimiaAvancada = new AlquimiaAvancada();
        BuscaPedraFilosofal missao = new BuscaPedraFilosofal(alquimiaAvancada);

        missao.RealizarMissao();
    }
}

```