A continuación se muestra un ejemplo del principio de segregación de interfaces. Suponemos una aplicación ficticia que debe enviar correos electrónicos o mensajes de texto. En una primera aproximación, podríamos pensar en algo así:


interface IMessageSender
{
    void sendToMail(string mail, string subject, string body);
    void sendSMS(string recipient, string message);
}

class MailMessageSender : IMessageSender
{
    public void sendSMS(SMSMessageDTO info) 
    { 
        /* No implementado */
    }

    public void sendSMS(MailMessageDTO info) 
    { 
        // Enviar correo
    }
}

De tal forma que el cliente utilizaría MailMessageSender para enviar un correo electrónico sería algo así:


void sendCustomMail( MailInfoDTO info )
{
    IMessageSender ms = new MailMessageSender();

    ms.sendToMail(info.mail, info.subject, info.body);
}

Con esta implementación, aunque funcione, estamos violando el principio ISP, ya que MailMessageSender está usando la interfaz ISendMessage pero sólo está implementado uno de sus dos métodos.

Lo correcto y evidente en este ejemplo de juguete, sería crear una interfaz específica:


interface IMailMessageSender
{
    void sendToMail(string mail, string subject, string body);
}

interface ISMSMessageSender
{
    void sendSMS(string recipient, string message);
}

class MailMessageSender : IMailMessageSender
{
    public void sendToMail(string mail, string subject, string body) 
    { 
        // Enviar correo
    }
}

class SMSMessageSender : ISMSMessageSender
{
    public void sendSMS(string recipient, string message) 
    { 
        // Enviar mensaje
    }
}

De este modo, cada interfaz define la funcionalidad exacta de su propósito y las clases que derivan de ellas implementan exactamente lo que necesitan, generando clases pequeñas, acotadas y, por tanto, más testeables.

Por último, siguiendo con el ejemplo, estamos haciendo sendCustomMail() dependiente de una implementación concreta de IMailSendMessage, violando así el principio de inversión de dependencias (DIP). Una mejor implementación sería así:


void sendCustomMail( MailInfoDTO info, IMailMessageSender ms )
{
    ms.sendToMail(info.mail, info.subject, info.body);
}

O bien de este otro modo utilizando una factoría de clases


void sendCustomMail( MailInfoDTO info )
{
    IMailMessageSender ms = _factory.getInstance();

    ms.sendToMail(info.mail, info.subject, info.body);
}

En ocasiones, con los ejemplos ilustrativos se pierde un poco la perspectiva de cómo aplicar estos principios en un proyecto real. A continuación extraigo un ejemplo de un sistema real en donde se ve claramente que se cumple el principio ISP en la implementación de un gestor particular de tareas escrito en C#:


class GatewayOrderRequestB11Task : ITask, 
    ITaskInitialize, 
    ITaskPerform, 
    ITaskProcess, 
    ITaskFinish, 
    ITaskPool 
{
    ....
}

¿Por qué leer El Libro Negro del Programador?

Adquirir desde:
Amazon (kindle eBook / papel)
CreateSpace (papel)
PayHip (epub / mobi / pdf)

El libro negro del programador.com
Segunda Edición - 2017

Archivo

Trabajo en...