Nenhuma classe deve ser dependente de métodos que não precisa.
Um exemplo seria uma interface “Máquina”, que força os métodos print( ), scan( ) e fax( ). Nem toda máquina tem esses 3 métodos.
Então criamos as interfaces IPrinter, IScanner e IFax. Agora uma máquina assina apenas os contratos que realmente precisa e cumpre apenas esses.
Exemplo de Código (Opcional - Ilustrando o texto):
// ❌ Anti-pattern: Interface genérica forçando métodos não utilizados
interface IMaquina {
print(): void;
scan(): void;
fax(): void;
}
// ✅ SOLID: Interfaces segregadas e específicas
interface IPrinter { print(): void; }
interface IScanner { scan(): void; }
interface IFax { fax(): void; }
A DEFINIÇÃO
Na prática, podemos entender o ISP como o conceito de que uma classe nunca deve depender de métodos que não utiliza.
A interface deve ser reutilizável em vários casos, logo uma interface engessada e com métodos em excesso atrapalha nesse processo.
Quando uma classe assina um contrato gigante, ela é obrigada a implementar métodos que não fazem sentido para o contexto dela, sujando o código e gerando acoplamento desnecessário.
UM MAU EXEMPLO
Contexto: Um sistema de blog onde todo user assina o mesmo contrato.
Aqui ferimos alguns conceitos que citei.
Exemplo de Código:
// RUIM: Interface obesa. Força comportamentos desnecessários.
interface IUserActions {
readPost(): void;
writePost(): void;
banUser(): void; // Usuário comum não deveria ver isso!
}
class StandardUser implements IUserActions {
public readPost(): void { console.log("Lendo..."); }
public writePost(): void { console.log("Escrevendo..."); }
// ERRO: O usuário comum é forçado a ter esse método
public banUser(): void {
throw new Error("Acesso Negado: Você não é administrador.");
}
}
DIVIDIR PARA CONQUISTAR
A solução no ponto de vista do ISP é clara, quebrar essa interface enorme em pequenos contratos bem escopados.
Quando for necessário mais de um contrato, pode ser construído um novo contrato com essa combinação específica ou o próprio assinante assumir mais de um contrato por vez (a depender da linguagem).
UM BOM EXEMPLO
Mesmo contexto, mas com escopos bem mais definidos.
Como é possível observar, apenas o necessário é assinado.
Exemplo de Código:
// BOM: Interfaces pequenas e específicas.
interface IReader { readPost(): void; }
interface IWriter { writePost(): void; }
interface IAdmin { banUser(): void; }
// O usuário comum implementa apenas o que ele realmente faz
class StandardUser implements IReader, IWriter {
public readPost(): void { console.log("Lendo..."); }
public writePost(): void { console.log("Escrevendo..."); }
}
// O Admin assina todos os contratos
class AdminUser implements IReader, IWriter, IAdmin {
public readPost(): void { console.log("Lendo..."); }
public writePost(): void { console.log("Escrevendo..."); }
public banUser(): void { console.log("Usuário banido!"); }
}
A LONGO PRAZO
Segregar interfaces deixa o seu código altamente modular. Se amanhã as regras de banimento de um IAdmin mudarem, a classe StandardUser não precisará ser tocada ou recompilada.
O seu sistema passa a ser construído como blocos de Lego, encaixando apenas as peças (contratos) que fazem sentido para aquela estrutura.
Meus Links
Github: victor-lis-bronzo
Linkedin: victor-lis-bronzo
Portfólio: portfolio.victorlisbronzo.me
Portfólio mais legal: victorlisbronzo.me
Deixe sua reação ❤️
Você tem o costume de criar várias interfaces pequenas ou acaba criando uma só para tudo?