Single Responsibility Principle

SRP é um modo de administrar as classes de um software de modo mais estratégico, melhorando aspectos como legibilidade para prevenir códigos complexos.

Categoria de Programação

Postado em 14 abril 2022

Atualizado em 14 abril 2022

Visualizações: 427



Single Responsibility Principle, ou SRP pode ser traduzido para “Princípio de responsabilidade individual”.

A entrada e saída de programadores nas empresas de TI não podem ser evitadas. É comum vermos novos programadores terem que lidar com o código de software mal planejado.

Isso traz muitas desvantagens na hora de fazer alterações no código ou adição de novas funcionalidades ao software, pois antes de tudo, o programador terá que compreender o código.

Com o princípio de responsabilidade individual implementado, é possível ter um código muito mais legível.

O que é SRP?

SRP é um modo de administrar as classes de um software de modo mais estratégico, melhorando os seguintes aspectos:

  • Melhor legibilidade
  • Melhor testabilidade
  • Prevenção contra algoritmos complexos
  • Melhor reutilização de classes e métodos
  • Redução de erros

Um classe só pode ter uma responsabilidade

No SRP cada classe só pode ter uma responsabilidade, e só pode mudar por uma razão.

Um exemplo de fácil entendimento é o aspirador de pó.

O aspirador de pó só tem uma função, aspirar a sujeira. Não podemos usar um aspirador de pó para lavar o carro.

Poderíamos até fabricar um aspirador que pode lavar o carro, porém isso tornaria o aspirador de pó muito complexo. Sua manutenção seria mais difícil podendo gerar mais gastos.

Invés de fabricar um aspirador de pó que também pode lavar carros, seria mais conveniente fabricar um aspirador de pó tradicional e uma máquina de lavar carros separadamente.

Essa é a idéia do SRP.

Prática

Considere o seguinte algoritmo:

class EntrevistaOnline {
    // Command
    public function comecar() {
        // Saudação
        echo "Bem vindo."
        
        // Inicia a instância Entrevistado
        $entrevistado = new Entrevistado();
        
        // Pergunta para inserir o seu primeiro nome
        echo "Insira o seu primeiro nome:"
        
        // Espera o usuário escrever
        $handle = fopen ("php://stdin","r");
        $line = fgets($handle);
        
        // Recebe o nome
        $nome = trim($line);
        
        // Passa o nome para a instância Entrevistado
        $entrevistado->nome = $nome;
        
        // Pergunta para inserir o seu sobrenome
        echo "Insira o seu sobrenome:"
        
        // Espera o usuário escrever
        $handle = fopen ("php://stdin","r");
        $line = fgets($handle);
        
        // Recebe o sobrenome
        $sobrenome = trim($line);
        
        // Passa o sobrenome para a instância Entrevistado
        $entrevistado->sobrenome = $sobrenome;
        
        // Validação
        if (is_null($entrevistado->nome)) {
            echo "Nome inválido";
            exit;
        }
        
        if (is_null($entrevistado->sobrenome)) {
            echo "Sobrenome inválido";
            exit;
        }
        
        echo "Prazer em conhecer, senhor(a) $entrevistado->nome $entrevistado->sobrenome";
    }
}

O código acima é totalmente contra os princípios da responsabilidade individual.

Se analisarmos atentamente o código acima, é possível afirmar as seguintes responsabilidades:

  • Mostrar mensagens
  • Solicitação de informação
  • Validação da informação inserida

Com tantas responsabilidades a classe fica inchada. Se imaginarmos um projeto muito maior com muito mais funcionalidades, isso viraria um grande pesadelo.

Se implementarmos o SRP aos poucos, o código irá ficar parecido com os exemplos abaixo:

class Saudacao {
    public static function saudar(): void {
        echo "Bem vindo."
    }
}

A classe acima só tem uma responsabilidade: fazer a saudação.

class Interrogador {
    public static function perguntar(string $informação): void {
        echo "Insira o seu $informação:";
    }
}

O interrogador é bastante parecido com a classe Saudacao, porém os dois tem tarefas diferentes. O interrogador

class CatadorDeNomes {
    public static function extrair(): string {
        $handle = fopen ("php://stdin","r");
        $line = fgets($handle);
        return trim($line);
    }
}

Extraímos a palavra inserida pelo usuário.

 class ObterInformaçõesEntrevistado {
    public static function obter(): Entrevistado {
        $entrevistado = new Entrevistado();
        
        // Nome
        Interrogador::perguntar('nome');
        $entrevistado->nome = CatadorDeNomes::extrair();
        
        // Sobrenome
        Interrogador::perguntar('sobrenome');
        $entrevistado->nome = CatadorDeNomes::extrair();
        
        return $entrevistado;
    }
}

Obtemos as informações do entrevistado. E retornamos a instância do entrevistado.

 class ValidatorDeEntrevistados {
    public static function estrevistadoTemNome(Entrevistado $entrevistado): bool {
        if (is_null($entrevistado->nome) || is_null($entrevistado->sobrenome)) {
            return false;
        }
        
        return true;
    }
}

Criamos um validator de entrevistados.

class FinalizadorDeEntrevista {
    public static function finalizar(Entrevistado $entrevistado): void {
        echo "Prazer em conhecer, senhor(a) $entrevistado->nome $entrevistado->sobrenome";
    }
}

Criamos a saudação final.

Com todas as classes prontas, implementamos as classes no código do primeiro exemplo.

class EntrevistaOnline {
    // Command
    public function comecar() {
        // Saudação
        Saudacao::saudar();
        
        // Entrevistado
        $entrevistado = ObterInformaçõesEntrevistado::obter();
        
        // Validação dos dados do entrevistado
        if (! ValidatorDeEntrevistados::estrevistadoTemNome($entrevistado)) {
            echo "Entrevistado com nome incompleto";
            exit;
        }
        
        // Finalização
        FinalizadorDeEntrevista::finalizar($entrevistado);
    }
}

Temos um código bem mais legível e fácil de realizar alterações.

Conclusão

Uma classe deve ter apenas uma responsabilidade. Se essa classe possui muitas responsabilidades o código torna-se complexo e consequentemente ilegível.