Princípio da Segregação de Interface
- Princípio da Responsabilidade Única
- Princípio do Aberto/Fechado
- Princípio de Substituição de Liskov
- Princípio da Inversão de Dependência
- Princípio da Segregação de Interface
Índice
O Princípio da Segregação de Interface (Interface Segregation Principle, ou ISP) é o quarto dos cinco princípios SOLID e foca em garantir que as interfaces sejam coesas e que as classes não sejam forçadas a depender de métodos que não utilizam. Ele afirma que:
“nenhum cliente deve ser forçado a depender de métodos que ele não usa.”
Em outras palavras, é preferível ter múltiplas interfaces menores e bem definidas, em vez de uma única interface grande que agregue responsabilidades demais.
O Problema da Interface “Gorda”
Uma interface gorda (ou “inchada”) é uma interface que define métodos que nem todas as classes que a implementam realmente necessitam. Isso leva a classes que têm que fornecer implementações para métodos que não fazem sentido no seu contexto, resultando em código desnecessário, menos coeso e mais difícil de manter.
O princípio da Segregação de Interface visa evitar esse problema ao incentivar o uso de interfaces mais específicas, que sejam diretamente relacionadas às responsabilidades de uma classe.
Problemas de Não Seguir o ISP
- Implementações Vazias ou Inúteis: Se uma classe forçada a implementar um método de uma interface que não faz sentido para ela, acaba tendo que fornecer implementações vazias ou que não fazem nada relevante.
- Acoplamento Desnecessário: Quando uma classe depende de métodos que não precisa, acaba criando um acoplamento desnecessário, aumentando a complexidade do sistema e tornando o código mais difícil de entender e manter.
- Baixa Reutilização: Interfaces inchadas tendem a ser menos reutilizáveis, pois nem todas as classes precisam de toda a funcionalidade descrita por elas.
Exemplo Prático em Dart
Vamos imaginar um cenário onde temos uma interface Worker
que descreve as responsabilidades de um trabalhador em uma empresa:
Interface que Viola o ISP:
abstract class Worker { void work(); void attendMeeting(); void manageTeam(); } class Developer implements Worker { @override void work() { print('Desenvolvendo código...'); } @override void attendMeeting() { print('Participando de uma reunião...'); } @override void manageTeam() { // Desenvolvedor não gerencia uma equipe throw UnsupportedError('Developers cannot manage a team'); } }
No exemplo acima, a interface Worker
define três responsabilidades: trabalhar, participar de reuniões e gerenciar equipe. No entanto, um desenvolvedor pode não ter a responsabilidade de gerenciar equipe, e a implementação desse método na classe Developer
gera uma exceção ou uma implementação vazia, o que é um sinal claro de violação do ISP.
Refatorando para Seguir o ISP:
Podemos dividir a interface Worker
em múltiplas interfaces menores, mais coesas, que garantem que cada classe implemente apenas os métodos que fazem sentido para ela:
abstract class Workable { void work(); } abstract class Attendee { void attendMeeting(); } abstract class TeamManager { void manageTeam(); } class Developer implements Workable, Attendee { @override void work() { print('Desenvolvendo código...'); } @override void attendMeeting() { print('Participando de uma reunião...'); } } class Manager implements Workable, Attendee, TeamManager { @override void work() { print('Trabalhando em táticas e estratégias...'); } @override void attendMeeting() { print('Participando de uma reunião...'); } @override void manageTeam() { print('Gerenciando a equipe...'); } }
No exemplo acima, dividimos a interface Worker
em três interfaces menores:
Workable
: Define o métodowork()
, que descreve a responsabilidade de realizar trabalho.Attendee
: Define o métodoattendMeeting()
, que descreve a participação em reuniões.TeamManager
: Define o métodomanageTeam()
, que descreve o gerenciamento de uma equipe.
Dessa forma, a classe Developer
implementa apenas as interfaces que fazem sentido para ela (Workable
e Attendee
), enquanto a classe Manager
implementa todas as interfaces que descrevem suas responsabilidades. Isso torna o código mais limpo, mais coeso e mais aderente ao princípio de Segregação de Interface.
Benefícios do Princípio da Segregação de Interface
- Classes Mais Coesas: As classes ficam focadas em suas responsabilidades reais, sem métodos desnecessários.
- Reutilização Aprimorada: Interfaces menores e bem definidas são mais fáceis de serem reutilizadas em outros contextos.
- Redução do Acoplamento: Como as classes não precisam implementar métodos que não utilizam, o acoplamento é reduzido, facilitando a manutenção e a evolução do sistema.
- Facilidade de Teste: Classes e interfaces menores são mais fáceis de testar, pois há menos funcionalidades para serem cobertas em cada unidade.
Resumo
O Princípio da Segregação de Interface nos ensina a evitar interfaces inchadas que forçam classes a implementar métodos desnecessários. Ao dividir interfaces grandes em múltiplas interfaces menores e coesas, podemos criar sistemas mais limpos, modulares e fáceis de manter. Isso resulta em um código mais flexível e que respeita o princípio de responsabilidade única, onde cada classe e interface foca apenas nas suas próprias responsabilidades.
Seguir o ISP é essencial para garantir que seu código permaneça simples, fácil de modificar e adaptável às mudanças nos requisitos do negócio ao longo do tempo, contribuindo para um design de software mais robusto e elegante.
Deixe uma resposta