David Lay

4 minute read

Los cinco principios de diseño de software SOLID fueron reunidos por Robert Martin (@unclebobmartin) a partir de varias ideas y papers pre-existentes en la comunidad. En estos artículos los revisaremos uno a uno con la interpretación desde mi experiencia con ellos y cómo han afectado mi forma de programar.

Todos los principios los puedes ver en el índice: http://www.davidlaym.com/2015/05/solid-resumen-de-los-principios

Principio de Segregación de Interfaces

La I de SOLID es por “Interface Segregation Principle” que se puede traducir como Principio de “Segregación de Interfaces”. Se define como:

Principio de Segregación de Interfaces

Principio de Segregación de Interfaces

Los clientes no deben ser forzados a depender de métodos que no utilizan

Cuando hablemos de interfaz, no estaremos hablando exclusivamente de el keyword en un lenguaje en particular, sino que del conjunto de métodos y propiedades públicas que expone una clase hacia sus clientes.

Este principio trata el caso de clases que, si bien cumplen con el SRP, los clientes que utilizan estas clases ocupan solo un subconjunto de los métodos presentados por su interfaz. En estos casos, este principio nos recomienda crear interfaces independientes para cada uno de los clientes, ya sea mediante herencia o implementación de «interface».

Un ejemplo sencillo

Un bus pub/sub es un ejemplo perfecto. Si no te ha tocado trabajar con ellos, son clases que se encargan de recibir mensajes y publicarlos a todos los subscriptores, como eventos, pero sin el acoplamiento que conllevan. Un diseño ultra simplificado de un bus sería:

Bus

Podemos deducir que un bus tiene dos tipos de clientes: subscriptores y publicadores. Aveces habrán algunos clientes que realicen ambas actividades, pero no es un caso típico. Esta clase respeta el SRP ya que tiene un solo motivo para cambiar: que cambie la forma de tratar los mensajes.

Un diseño que respete el ISP sería:

AbstractBusSin embargo este diseño es muy poco flexible y obliga a tener instancias separadas para cada uno de los roles. Además en la mayoría de los lenguajes, este diseño es muy complicado de implementar debido a que el publicador debe conocer los subscriptores, debiendo compartir de alguna forma las estructuras de datos internas.

Un diseño más práctico es el siguiente:

InterfaceBusDe esta forma se puede tener una sola instancia como singleton, que maneja todos las estructuras de datos internas,  pero los clientes podrán depender de la interfaz que utilicen. Si usan ambas interfaces (esos raros casos) pueden depender de ambas o depender de la clase directamente.

Es difícil apreciar a primera instancia los problemas que se pueden generar al violar este principio, o los beneficios que se obtienen al cumplirlo, ya que parece algo muy inocuo y normal tener clases para los que distintos clientes utilicen distintos métodos, por lo que veremos algunos de los que considero más importantes:

Intencionalidad

Al cumplir con ISP, mejoramos la intencionalidad de nuestro código, compara lo siguiente:

public class AlgunaClaseEnTuCodigo {

    // constructor
    public AlgunaClaseEnTuCodigo(Bus bus) { 
        // implementación omitida
    }
}

 

public class AlgunaClaseEnTuCodigo {

    // constructor
    public AlgunaClaseEnTuCodigo(BusSubscriber subscriber) { 
        // implementación omitida
    }
}

Los dos trozos de código son casi idénticos, excepto en los componentes de los que dependen. En el segundo caso podemos determinar que esta clase se subscribe en algún momento al bus solamente leyendo la firma del constructor. En el primer caso no podemos saber nada sobre el uso que se le dará al bus del cual depende.

Esto es intencionalidad, quiere decir, nuestra codificación refleja la intención con la cual se realizan las decisiones de diseño. Es muy importante para mantener nuestro código fácil de mantener en el tiempo.

Pruebas unitarias

Al realizar pruebas unitarias, se nos simplifica mucho más la tarea si tenemos que realizar fakes o mocks a interfaces más sencillas. Es súper simple, pero las pequeñas mejoras suman y suman.

Simplificación de jerarquías

Al cumplir con ISP, pavimentamos el camino para simplificar las jerarquías de clases.

Para mi este es uno de los grandes beneficios del ISP. En el ejemplo de este artículo no se puede apreciar, pero no es difícil recordar alguna clase que tenía tres o cuatro niveles de herencia en alguno de los proyectos que hemos trabajado. Es algo que normalmente sucede. Es posible que esa cadena de herencias cumpla con el SRP, incluso posible que respete el LSP,  pero es muy probable que no respete el ISP simplemente porque al heredar tantos métodos la interfaz pública es simplemente un asco. Respetar el ISP generalmente lleva a tomar la decisión no solo de separar interfaces, sino que mediante aquello también deshacer esas jerarquías y remplazar la herencia por colaboración de componentes, que es un modelo mucho más flexible en el largo aliento.

 

comments powered by Disqus