I'm writing a Websocket implementation in Java, and I've set it up so that it basically just wraps an InputStream and OutputStream, and has public methods for both sending and receiving.  While input and output are related, they're also complete opposites, and share very little functionality.  Would it make more sense to have WebsocketInput and WebsocketOutput classes instead?Java's Socket class really has no methods for sending and receiving, other than providing an InputStream and OutputStream.  I'm not aware of any commonly used classes in Java that encapsulate both reading and writing, but it feels wrong to split them up here, since no user would have much of a use for one half of a Websocket.  What would be the best approach here?
Does a full duplex communication object conflict with single responsibility?
java;single responsibility;sockets;io;websockets
In addition to the other very good answers here, one way to think about it is that you are not really improving the level of abstraction (in the direction of a full duplex capability) by applying individual wrappers to the input & output streams.While it is true that the input & output streams are individually providing their own single responsibility when viewed at their level of abstraction: on the other hand, the bundle of input & output put together forms a higher level of abstraction, the full duplex stream.  Having a higher level of abstraction, when we look it it that way: it has its own single responsibility, the pairing of an appropriate input & output stream to form a full duplex com link.One hint that suggests you are raising the level of abstraction by combining the two together because now you have a single entity that will provide full duplex, and you can pass around to others, and especially whereas by comparison: If you wrap input & output individually and separately, you would (still) have two abstractions to pass around, and clients would have to concern themselves with (potentially the details of) pairing the two, if not at least keeping them together when passed around, to form the full duplex abstraction. (You could still put a wrapped input & an output together to finally manifest a good full duplex abstraction, but then what's the point of the intermediate wrappers?)So, while the underlying unidirectional streams each have their own single responsibility, so does a class that bundles them together have its own single responsibility.  These are not mutually exclusive: because the latter is at a higher level of abstraction.  Taken together these classes are exhibiting layering, which is one way to keep designs focused on their single responsibility.  Layering is where one abstraction is implemented entirely by abstractions at the next layer below, without having to go any lower.  (Layering is a technique I like to reduce complexity of very large software projects.)