Posts SOLID - Interface Segregation Principle
Post
Cancel

SOLID - Interface Segregation Principle

SOLID: Interface Segregation Principle (ISP)

Apesar do nome sugerir complexidade, o ISP é um dos princípios mais simples e diretos na minha opinião.

Basicamente, segregar as interfaces, ou seja, torná-las granulares, ajuda a evitar sobrecarregar interfaces com métodos que não todos os seus subtipos precisam.

Imagine que precisamos construir uma classe para calcular os valores de um empréstimo. Cada tipo de empréstimo terá uma forma de implementar CalculadoraEmprestimo, por exemplo, CalculadoraEmprestimoPessoal e CalculadoraEmprestimoEmpresarial.

1
2
3
4
5
6
7
8
9
10
11
package org.example;

import java.util.List;

public interface CalculadoraEmprestimo {

  List<Juro> calcularJuros();
  List<Taxa> calcularTaxas();
  List<Tarifa> calcularTarifas();
  
}

Perceba que a classe acima viola o ISP, pois CalculadoraEmprestimoPessoal não precisa calcular tarifas. A interface nos força a implementar calcularTarifas, o que resultaria em uma exceção se fosse utilizada, tornando sua utilização confusa.

Se futuramente um novo tipo de empréstimo fosse criado, e não fosse necessário calcular taxas, teríamos mais problemas. Estaríamos carregando mais bagagem do que o necessário na interface, violando assim o ISP.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package org.example;

import java.util.List;

public interface CalculadorJuros {
    List<Juro> calcularJuros();
}

public interface CalculadorTaxas {
    List<Taxa> calcularTaxas();
}

public interface CalculadorTarifas {
    List<Tarifa> calcularTarifas();
}

Acima está um exemplo simples de como solucionar o problema do ISP. Separamos de forma concisa e granular entre interfaces. Assim, o cliente pode combinar interfaces para atingir seu objetivo.

1
2
3
4
5
6
7
8
9
10
11
public class CalculoEmprestimoPessoal implements  CalculadorJuros, CalculadorTaxas {
  @Override
  List<Juro> calcularJuros() {
    // impl
  }

  @Override
  List<Taxa> calcularTaxas() {
    // impl
  }
}

O princípio do ISP pode ser estendido ao nível de pacotes e arquitetura. Por exemplo:

isp_problem_package

No desenho acima, imagine que os Apps utilizem o mesmo framework. Porém, esse framework utiliza um banco de dados. O App B não faz uso do banco de dados, pois apenas utiliza as funcionalidades do framework relacionadas a alguns utilitários de abstração de banco de dados. Considere o seguinte cenário de versionamento semântico:

  • v1.0.0: Versão utilizada por ambos os APPs no estado inicial.
  • v1.2.0: Feature com novos campos no banco de dados (Apenas para o App A).
  • v1.2.1: Correção de segurança (por exemplo, uma vulnerabilidade como a do log4j).

Desde o início, o App A e B utilizam o mesmo framework. Devido a esse acoplamento com o banco de dados, o App B precisa carregar dependências e recursos dos quais não precisa. O melhor cenário seria fragmentar o framework, permitindo assim combinar ou não essas partes.

Conclusão

O Princípio da Segregação de Interfaces (ISP) é fundamental para manter as interfaces coesas e evitar que os clientes de uma interface dependam de métodos que não necessitam. Ao dividir interfaces em unidades menores e mais específicas, podemos criar sistemas mais flexíveis e fáceis de manter. Além disso, a aplicação do ISP pode se estender além do nível da interface, alcançando também o design de pacotes e arquitetura do sistema, reduzindo o acoplamento e melhorando a modularidade.

This post is licensed under CC BY 4.0 by the author.