SOLID: Principio de Segregación de Interfaces
Tags: oop, spanish, solid, architecture
Published: 2021-05-24 18:35:40

Este principio fue desarrollado por Robert C. Martin mientras trabajaba como consultor en Xerox. Durante su periodo laboral, Martin estuvo a cargo del desarrollo de un nuevo sistema de gestión de impresiones, que permitía realizar diferentes acciones concurrentes en una nueva línea de impresoras.  

A lo largo del desarrollo notó que pequeñas modificaciones al sistema terminaban en largos despliegues a producción, en muchos casos, en despliegues de módulos fuera del alcance de los cambios. El origen del problema era una interfaz sobrecargada con diferentes firmas de métodos que era utilizada en todas las acciones concurrentes que desempeñaba el sistema. Es decir, si Martin realizaba modificaciones en los módulos de impresión, los cambios se propagaban a los otros módulos, como el de faxeo, escaneo, etc. 

La solución dada por Robert C. Martin a este problema, es lo que hoy conocemos como el Principio de Segregación de Interfaces. 

La definición del principio es la siguiente:

> Ningún cliente debe de ser forzado a depender de una interfaz que no utiliza.

El principio es bien sencillo, ninguna clase debe de ser forzada a implementar métodos de interfaces que no utiliza. El objetivo, al igual que el principio de responsabilidad única, es limitar el alcance de los cambios a futuro.

## Violación al Principio de Segregación de Interfaces

Supongamos que eres el desarrollador a cargo del sistema de gestión de la nueva línea de impresoras multifuncionales de Xerox. Este nuevo sistema se desarrollará desde cero, por lo tanto estarás a cargo de los futuros desarrollos de las diferentes impresoras que se originen de la nueva línea de multifuncionales. 

Esta nueva línea cuenta con las siguientes capacidades:

* Impresión.
* Escaneo.
* Faxeo.

```java
public interface MultifuncionalLX {
    
    /**
     * Método encargado de imprimir el siguiente documento 
     * activo en la cola de impresión.
     * 
     * @return      Retorna boolean indicando el resultado.
     */
    public boolean imprimirDocumento();
    
    /**
     * Método encargado de escanear el documento cargado
     * en la bandeja de escaneo.
     * 
     * @return      Retorna boolean indicando el resultado.
     */
    public boolean escanearDocumento();
    
    /**
     * Método encargado de faxear el documento cargado
     * en la bandeja de faxeo.
     * 
     * @return      Retorna boolean indicando el resultado.
     */
    public boolean faxearDocumento();
}
```
Para llevar a cabo el desarrollo se define la siguiente interfaz. La cual establece los métodos básicos que tendrán las multifuncionales de la nueva línea.

```java
public class ImpresoraLX8578 implements MultifuncionalLX {

    @Override
    public boolean imprimirDocumento() {
        //Lógica de impresión de documentos
        return true;
    }

    @Override
    public boolean escanearDocumento() {
        //Lógica de escaneo de documentos
        return true;
    }

    @Override
    public boolean faxearDocumento() {
        //Lógica de faxeo de documentos
        return true;
    }
    
}
```
*Para facilitar la compresión del ejemplo, se omitió la implementación especifica de cada método.*

Durante varios meses se lanzan diferentes versiones de la multifuncional, las cuales utilizan la misma interfaz para definir sus funcionalidades principales. 

Gracias a la aceptación de la nueva línea de impresoras. Gerencia, te solicita la integración de l sistema de gestión de impresiones a una nueva impresora económica, que será lanzada bajo la línea de impresoras que esta bajo tu responsabilidad. La diferencia es que esta nueva impresora no contará con la capacidad de enviar faxes, únicamente impresión y escaneo.

Tomando en cuenta que esta nueva impresora pertenece a la misma línea que las impresoras anteriores y también es categorizada como multifuncional, decides utilizar la interfaz definida para dicha línea.

```java
public class ImpresoraLX8590 implements MultifuncionalLX {

    @Override
    public boolean imprimirDocumento() {
        //Lógica de impresión de documentos
        return true;
    }

    @Override
    public boolean escanearDocumento() {
        //Lógica de escaneo de documentos
        return true;
    }

    @Override
    public boolean faxearDocumento() {
        throw new UnsupportedOperationException("Impresora no cuenta con la capacidad de faxeo."); 
    }
    
}
```
En este punto es donde se da la violación al Principio de Segregación de Interfaces, debido a que la impresora __ImpresoraLX8590__  es forzada a depender de métodos que no utiliza.

## Implementación del Principio de Segregación de Interfaces

La solución al ejemplo anterior, es la segregación de la interfaz que agrupa todos los métodos en diferentes interfaces especializadas. Por lo tanto, la interfaz __MultifuncionalLX__ se convertirá en las interfaces:

* MultifuncionalLXImpresion
* MultifuncionalLXEscaneo
* MultifuncionalLXFaxeo  

```java
public interface MultifuncionalLXEscaneo {
    
    /**
     * Método encargado de escanear el documento cargado
     * en la bandeja de escaneo.
     * 
     * @return      Retorna boolean indicando el resultado.
     */
    public boolean escanearDocumento();
}

public interface MultifuncionalLXFaxeo {
    
    /**
     * Método encargado de faxear el documento cargado
     * en la bandeja de faxeo.
     * 
     * @return      Retorna boolean indicando el resultado.
     */
    public boolean faxearDocumento();
}

public interface MultifuncionalLXImpresion {
    
    /**
     * Método encargado de imprimir el siguiente documento 
     * activo en la cola de impresión.
     * 
     * @return      Retorna boolean indicando el resultado.
     */
    public boolean imprimirDocumento();
}
```
Se modifican las clases de las impresoras anteriores para que utilice las interfaces especializadas.

```java
public class ImpresoraLX8578 implements MultifuncionalLXEscaneo, 
        MultifuncionalLXFaxeo,
        MultifuncionalLXImpresion{

    @Override
    public boolean imprimirDocumento() {
        //Lógica de impresión de documentos
        return true;
    }

    @Override
    public boolean escanearDocumento() {
        //Lógica de escaneo de documentos
        return true;
    }

    @Override
    public boolean faxearDocumento() {
        //Lógica de faxeol de documentos
        return true;
    }
    
}
```
Se define la clase __ImpresoraLX8590__ únicamente con las interfaces de escaneo e impresión.
```java
public class ImpresoraLX8590 implements MultifuncionalLXEscaneo, 
        MultifuncionalLXImpresion{

    @Override
    public boolean imprimirDocumento() {
        //Lógica de impresión de documentos
        return true;
    }

    @Override
    public boolean escanearDocumento() {
        //Lógica de escaneo de documentos
        return true;
    }
    
}
```
Las modificaciones realizadas permiten que el código se encuentre en cumplimiento con el Principio de Segregación de Interfaces.

##Diferencia entre el Principio de Segregación de Interfaces y el Principio de Sustitución de Liskov

Algunos desarrolladores pueden confundir estos dos principios SOLID. Sin embargo, ambos se enfocan en diferentes aspectos puntuales en el diseño de la programación orientada a objetos.

El Principio de Sustitución de Liskov se enfoca en subtipos y herencia, se enfoca en que los subtipos de una clase cumplan con el contrato especificado en la clase abstracta. Por otro lado, el Principio de Segregación de Interfaces se enfoca en segregar interfaces grandes en interfaces especializadas, así las clases que implementen dichas interfaces no dependan de interfaces y métodos que no utilizan.

## Cuando utilizar el Principio de Segregación de Interfaces

Este principio, al igual que el principio de responsabilidad única, es clave para limitar el alcance de los cambios futuros en el diseño de las aplicaciones. Sin embargo, es muy difícil detectar estas violaciones durante las primeras iteraciones de la solución. Lo mejor es permitir que la solución evolucione para poder identificar los puntos claves en donde se puede aplicar este principio.

Si deseas ampliar tu conocimiento acerca del Principio de Segragación de Interfaces, puedes consultar el blog de [Robert C. Martin](https://blog.cleancoder.com/uncle-bob/2020/10/18/Solid-Relevance.html).

En la próxima publicación discutiremos acerca del último principio SOLID, el Principio de Inversión de Dependencias.