Skip to main content

Is it bad practice to create an interface only to combine two other interfaces? [Resolved]

I'm working on an infrastructure for inter process communication. I have created two interfaces, one to send data and another one to listen to data being sent:

public interface ISender : IDisposable
{
    void Send(T dataToSend);

    void Disconnect();
}

public interface IListener : IDisposable
{
    event EventHandler> DataReceived;

    void Connect();

    void Disconnect();
}

I've also created another interface to allow two way communication:

public interface ICommunication : IListener, ISender
{

}

But I'm not entirely comfortable with the fact that this interface is just combining the previous two interfaces and not adding anything.
To me, it feels to much like a marker interface (even though it's not).

So the question is, do you think it's bad practice, and if so, can you provide another alternative?


Question Credit: Zohar Peled
Question Reference
Asked April 16, 2019
Tags: , interfaces
Posted Under: Programming
34 views
3 Answers

Thanks to everyone that commented or answered my question.

After carefully considering all the information everyone provided on this question, I've decided to not include the ICommunication interface after all.

I've came to this conclusion based on both Karl's and Flater's answers and on the last comments by Liav and Kain0_0 - so instead of marking any of the existing answers as accepted, I better post an answer myself and accept it - so here are my reasons:

  • The first part of Flater's last paragraph:

    it's good practice to keep responsibilities separated as best as you can

  • From Liav's last comment:

    Do you have components that are both things at the same time (sender and listener)? If yes, then it couldt make sense. However, don't you think such component have too many reasons to change?

  • From Karl's answer:

    Do you ever have a list of ICommunication in your calling code, or is that purely because you noticed some things are both and you wanted to classify it as such?

  • Kain0_0's first comment:

    Does IComminucation define a richer expected behaviour then IListener + ISender? Yes then this is fine, there is someone out there expecting this richer behaviour. No then just inherit each interface directly and pass the object as the IListener and as the ISender to whomever needs them.

All things considered, I've decided it's probably a bad practice to have the IComminucation interface.


credit: Zohar Peled
Answered April 16, 2019

The way to determine if this is advisable for your use case is to look at the calling code. Do you ever have a list of ICommunication in your calling code, or is that purely because you noticed some things are both and you wanted to classify it as such? A subtype relationship is a very strong form of coupling, so you don't want to create it unless you actually need to use it.

That goes for the ISender and IListener as well, for that matter. If you never have a situation where you need one but not the other in the calling code, the interface segregation principle doesn't require you to separate them just because they feel like different things and you want to classify them accordingly. An interface is a working relationship, not a descriptive one.


credit: Karl Bielefeldt
Answered April 16, 2019

The core question here is whether you're ever going to have an explicit requirement for an object to implement both interfaces.

When you don't, that means that you're only doing it to save some characters in the class definition, which is not enough of a justifiable reason to create this pseudo-marker-interface.

However, if there is an actual need for an object which does both, then it does become relevant.

Suppose you're trying to create a method in which you need to send and receive data. Since these are two separate responsibilities, you're likely going to split these out anyway:

public void Synchronize(ISender<int> sender, IReceiver<int> receiver)
{
    sender.Send(myInt);
    myInt = receiver.Receive();
}

Even if you wish to use a class that just happens to implement both interfaces, you can simply pass in the same object:

Synchronize(myCommunicationObject, myCommunicationObject);

At this point, you don't need the joined interface, because the send/receive responsibilities are two separate tasks. However, if your business logic requires that you exchange data with the same object (for whatever reason), then the above method makes it impossible to prevent that sender and receiver are the same object (and no, an equality check and possible exception is of course not a good way to solve this).

This is where the joined interface becomes relevant, because you now have an explicit need for a single object with both send/receive capabilities. When you create this interface, it becomes possible to enforce sending/receiving over the same channel:

public void Synchronize(ICommunication<int> channel)
{
    channel.Send(myInt);
    myInt = channel.Receive();
}

This may not apply to your current use case, but there are cases in which this would be a valid solution.

The core of the answer here is that it's good practice to keep responsibilities separated as best as you can, but when there is an explicit need for two responsibilities to be conjoined, then creating that conjoined responsibility is the most sensical approach.


credit: Flater
Answered April 16, 2019
Your Answer