dev-resources.site
for different kinds of informations.
ISP - O Princípio da Segregação de Interface
O ISP (Interface Segregation Principle) foi formulado e utilizado pela primera vez por Robert C. Martin (o famoso Uncle Bob), enquanto ele realizava uma consultoria para a Xerox.
Este princípio, na minha opnião, é o mais simples dos 5 Princípios SOLID e, ao mesmo tempo, o mais negligenciado dentre os desenvolvedores e arquitetos de software. No entanto, isso depende muito da linguagem de programação utilizada.
Linguagens dinamicamente tipadas, como o Python por exemplo, não forçam qualquer tipo de implementação. Isso acontece devido ao fato de as declarações serem inferidas em tempo de execução.
Definição do ISP
Não trouxe nenhuma frase bonita escrita (ou dita) por alguma estrela da arquitetura de software, mas podemos definir e afirmar que:
A segregação de interface deve ser realizada sempre que um tipo/classe estiver sendo forçado a implementar um atributo e/ou um comportamento sem sentido e/ou sem propósito.
Como de costume: Calma e respira... Está tudo bem!
Vamos seguir com os exemplos e, caso não tenha entendido, eu garanto que você vai sair desta página totalmente esclarecido.
Violação do ISP
Podemos imaginar um cenário simples onde temos uma interface IPrinter
que possui dois métodos: Print
e Scan
. Nosso programa possui duas classes que implementam essa interface, denominadas AdvancedPrinter
e BasicPrinter
.
A classe AdvancedPrinter
pode imprimir e escanear documentos, e por isso implementa ambos os métodos. Já a classe BasicPrinter
pode apenas imprimir documentos, portanto implementa apenas o método Print
e lança uma exceção caso o método Scan
seja acionado. Segue o código com este exemplo:
public record Document(string Name, string Content);
public interface IPrinter
{
void Print(Document document);
Document Scan();
}
public class AdvancedPrinter : IPrinter
{
public void Print(Document)
{
// Lógica para impressão do documento.
}
public Document Scan()
{
// Lógica para escanear um documento.
}
}
public class BasicPrinter : IPrinter
{
public void Print(Document)
{
// Lógica para impressão do documento.
}
public Document Scan()
{
throw new NotImplementedException(
"Esta impressora não pode escanear documentos.");
}
}
Situações como esta são mais comuns do que você pode imaginar. Acho complicado e triste falar sobre isso mas, em mais de dez anos de carreira, testemunhei este tipo de abordagem muitas e muitas vezes...
Não sou hipócrita e muito menos um santo para dizer que nunca fiz nada parecido. Afinal, ninguém chega no mundo da programação com todas as boas práticas e princípios decorados prontos para serem executados. Não é mesmo?
Tudo isso faz parte do processo de crescimento de todo bom desenvolvedor e arquiteto de software.
Mas se você ainda tem dúvidas do que deveria ser feito neste caso, não se preocupe! Este artigo foi escrito com muito carinho para ajudar pessoas como você! Pessoas que têm o brilho nos olhos e o interesse em construir códigos de qualidade.
Aplicação do ISP
Para ficar em conformidade com o Princípio da Segregação de Interface e resolver este problema é realmente muito simples!
Seguindo uma abordagem similar à utilizada no artigo sobre LSP, precisamos separar os comportamentos em interfaces distintas e implementá-las apenas quando forem realmente necessárias.
Sendo assim, podemos corrigir o exemplo apresentado há pouco da seguinte forma:
public record Document(string Name, string Content);
public interface IPrinter // Possui apenas o método de impressão.
{
void Print(Document document);
}
public interface IScanner // Possui apenas o método de escaneamento.
{
Document Scan();
}
public class AdvancedPrinter
: IPrinter, IScanner // Implementa ambas as interfaces.
{
public void Print(Document)
{
// Lógica para impressão do documento.
}
public Document Scan()
{
// Lógica para escanear um documento.
}
}
public class BasicPrinter
: IPrinter // Implementa apenas a interface com método de impressão.
{
public void Print(Document)
{
// Lógica para impressão do documento.
}
}
Como eu disse, é muito simples. Lançar exceções ou implementar métodos vazios simplesmente porque a classe X não consegue atender ao comportamento da interface Y não é uma boa prática. Pense sempre na coerência, durabilidade e longevidade do seu código.
Espero que você tenha compreendido a mensagem e que este artigo tenha sido realmente útil e esclarecedor para você.
Me siga para receber mais conteúdos como este. ❤️
Recomendação de leitura:
Arquitetura Limpa - O Guia do Artesão para Estrutura e Design de Software
Robert Cecil Martin, 2019.
Featured ones: