c#

interface segregation main purpose and uses of interface c sharp

A
Desh-Duniya Team Author
| Published September 16, 2019

interface segregation main purpose and uses of interface c#

According to Wikipedia the interface segregation principle (ISP) states that no client should be forced to depend on methods it does not use. For the sake of this post I will use the term “server” to describe a class in an API – a business object for example. “Client” will be used to describe the consumer of a service – it could be a user interface component for example. The client has a dependency on a server at some level, the server knows nothing about a client.

As an example, let’s assume a team responsible for creating the server was tasked with creating a basic email object. Being good programmers, they designed to an interface and came up with the following Interface and implementation.

public interface IMessage
    {
        IList<String> ToAddresses { get; set; }
        string MessageBody { get; set; }
        string Subject { get; set; }
        bool Send();
    }

    public class SmtpMessage:IMessage
    {
        public IList<String> ToAddresses { get; set; }
        public string MessageBody { get; set; }
        public string Subject { get; set; }

        public bool Send()
        {
            //Do the real work here
            return true;
        }
    }

Client Team A, responsible for creating an application that sends an email reminder as a part of their process, creates a client that consumes the server, and everything works. Now assume the server team gets a new requirement, from Client Team B, and now they need to support sending a text message. That’s almost the same as sending an email message so they decide to be polymorphic and use the IMessage interface.

public class SmsMessage : IMessage
    {
        public IList<String> ToAddresses { get; set; }
        public string MessageBody { get; set; }
        public bool Send()
        {
            //Do the real work here
            return true;
        }
        public string Subject
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }
    }

Client Team B is happy, things work great and Client Team A is happy because now they can send SMS messages if they want to. Client Team A wants to enhance their system to allow for a list of addresses to be included as a blind copy, so they give the Server team this new requirement. The server team comes up with the following change to the interface and new implementations:

public interface IMessage
    {
        IList<String> ToAddresses { get; set; }
        string MessageBody { get; set; }
        string Subject { get; set; }
        bool Send();
        IList<String> BccAddresses { get; set; }
    }

    public class SmtpMessage:IMessage
    {
        public IList<String> ToAddresses { get; set; }
        public IList<String> BccAddresses { get; set; }
        public string MessageBody { get; set; }
        public string Subject { get; set; }

        public bool Send()
        {
            //Do the real work here
            return true;
        }
    }

    public class SmsMessage : IMessage
    {
        public IList<String> ToAddresses { get; set; }
        public string MessageBody { get; set; }
        public bool Send()
        {
            //Do the real work here
            return true;
        }
        public string Subject
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }
        public IList<string> BccAddreses
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }
    }

Client Team A gets the new server and things are great, but Client Team B is now broken and must recompile and go through a round of regression testing because a feature was added for another team.

The main goal of the interface segregation principle is to loosen the coupling between servers and their clients. An SMS message supports a list of addresses, a message body, and the notion of sending but Client B was unnecessarily also coupled to the Subject and eventually the BccAddressList property. In short, a change to Any unused property or method or a change to an overly broad interface itself will cause Team B problems. Let’s rework things a little bit and see if we can improve the design.

public interface IMessage
    {
        IList<String> ToAddresses { get; set; }
        string MessageBody { get; set; }
        bool Send();
    }

    public interface IEmailMessage:IMessage
    {
        string Subject { get; set; }
        IList<String> BccAddresses { get; set; }
    }

    public class SmtpMessage : IEmailMessage
    {
        public IList<String> ToAddresses { get; set; }
        public IList<String> BccAddresses { get; set; }
        public string MessageBody { get; set; }
        public string Subject { get; set; }
        public bool Send()
        {
            //Do the real work here
            return true;
        }
    }

    public class SmsMessage : IMessage
    {
        public IList<String> ToAddresses { get; set; }
        public string MessageBody { get; set; }
        public bool Send()
        {
            //Do the real work here
            return true;
        }
    }

With this design we have a nice crisp IMessage definition that will serve Client B very well in that the client does not depend on any methods it does not use. We have created a “wider” interface Called IEmailMessage that inherits from IMessage for Team A to use so Team A can send Email or an SMS text message.

If we want to remove the requirement that a Client understand it needs to set the address list and message body before calling the send method, we could also do this:

public interface IMessage
    {
        bool Send(IList<String> toAddresses, string messageBody);
    }

    public interface IEmailMessage:IMessage
    {
        string Subject { get; set; }
        IList<String> BccAddresses { get; set; }
    }

    public class SmtpMessage : IEmailMessage
    {
        public IList<String> BccAddresses { get; set; }
        public string Subject { get; set; }
        public bool Send(IList<String> toAddresses, string messageBody)
        {
            //Do the real work here
            return true;
        }
    }

    public class SmsMessage : IMessage
    {
        public bool Send(IList<String> toAddresses, string messageBody)
        {
            //Do the real work here
            return true;
        }
    }

Discussion (0)

Please sign in to participate in the discussion.
No comments yet. Be the first to join the conversation!