Princípio de Segregação de Interfaces

Princípio de Segregação de Interfaces (Interfaces Segregation Principle)

Este príncipio versa sobre o design de interfaces. Interfaces são como classes abstratas, mas que não implementam comportamento. São apenas o conjunto das assinaturas dos métodos que alguma outra classe irá implementar. Por exemplo, a classe abaixo define as quatro operações aritmeticas:

interface Numeral {

    Numeral plus(Numeral other);
    Numeral minus(Numeral other);
    Numeral multiply(Numeral other);
    Numeral divide(Numeral other);

}

Não definimos como iremos implementar estas operações, apenas definimos as operações em si.

O que o Princípio de Segregação de Interfaces dita é que:

Uma classe não deve ser obrigada a implementar um contrato que não pode cumprir.

No nosso caso acima, se pensarmos em números racioanais todas aquelas operações são possiveis, mas para números inteiros não pois a divisão de um inteiro por outro inteiro nem sempre é um inteiro.

Poderiamos pensar que podemos reutilizar a operação de divide e realizar a divisão inteira, só que isso seria uma violação do contrato original de Numeral. Para dois Numeral a e b o contrato implica que

 var q = a.divide(b);
 assert a == q.multiply(b);

Mas para inteiros precisamos duas operações: a divisão inteira e o resto (remainder).

 var q = a.integerDivide(b);
 var r = a.reminder(b);
 assert a == q.multiply(b).plus(r);

Então uma classe Integer não poderia implementar Numeral, equanto que uma classe Rational poderia. O que o Princípio de Segregação de Interfaces indica é que a solução está em segregar as interfaces, ou seja, fazer interfaces diferentes.

Nesse caso fariamos um interface apenas para as operações de soma, uma apenas para as operações de multiplicação e outra ainda para as de divisão:

interface Summable {
    Summable plus(Summable other);
}

interface Multipliable {
    Multipliable plus(Multipliable other);
}

interface Divisable {
    Divisable divide(Divisable other);
}

interface IntegerDivisable {
    IntegerDivisable integerDivide(IntegerDivisable other);
    IntegerDivisable remainder(IntegerDivisable other);
}

Assim, poderiamos construir as classes Rational e Integer:

interface Rational extends Summable, Multipliable, Divisable {

}

interface Integer extends Summable, Multipliable, IntegerDivisable {

}

Então, para operações de soma e multiplicação, podemos usar qualquer uma das duas, mas para divisões depende de que divisão queremos.

A API de Coleções

A API de coleções do Java não segue este principio completamente. Uma interface List, por exemplo, sempre tem métodos para adicionar, substituir e remover elementos, independentente se a implementação é imutável ou não. Para os casos em que a operação não é desejável ou não ha implementação, uma exceção é lançada.

A não segregação de interfaces nestes caso dificulta o uso, pois podemos tentar invocar um método que não tem implementação e obter uma exceção, violando o Principio da Mínima Surpresa.

Esta falta de segregação também obriga a uma falha em seguir o Príncípio de Substituição de Liskov

Origem Histórica

O Príncipio de Segregação de Interfaces foi proposto por Robert C. Martin num artigo, em 1996.

Também pela mão de Robert C. Martin este princípio entrou para o top 5 dos Principios de Orientação de Objetos, juntos conhecidos como os "Principios SOLID" (SOLID Principles) num trocadilho de palavras sugerindo que seguir os princípios SOLID, tornaria o código sólido, por oposição a frágil. O Princípio de Segregação de Interfaces corresponde ao I pelo seu nome em inglês: Interface Segregation Principle.

Scroll to Top