Suppose that I have an input stream interface, which defines a method for reading data. I also have a seekable interface which defines a method for seeking. A natural way of defining a input file is then to implement both input stream and seekable.
I want to construct a data decoder from the input stream interface so I can read data from a file or from another stream. The problem is that I also want to implement seek functionality to the data decoder, since I want to be able to step individual records not raw bytes. This is not possible if I only provide an input stream, which does not have the bytewise seek method.
Should I skip the seekable interface and add the seek method to input stream instead and force all streams to at least leave it as a nop.
EDIT: The decoder does not need to seek if the client does not request a seek operation. Also the stream is associated with the decoder and cannot be changed after initialization
3
The way the .NET guys solved this problem was to introduce a property IsSeekable
that allow to know if a Stream
can be seeked. If not and you call Seek()
anyway, it throws an exception. It’s not very polymorphic but it’s simple and works reasonably well in practice. It allows Stream to be passed around freely and each method can optimise for seeking if it want. The downside is that any method that want to use Seek()
need to check the property before.
A more object oriented approach would be to create the interface SeekableInputStream
that derives from both Seekable
and InputStream
. That way a class that needs to seek like your data adapter can require that specific interface and be guaranteed that seek will work. Better yet, the compiler will warn you if you try to send an invalid InputStream
to such method. Other method can accept any class that implements InputStream
, including those that implement SeekableInputStream
. The downside to this method is that if you pass your SeekableInputStream
around a lot then once its downcasted to InputStream
the information about its seekability is lost and you need to cast it to SeekableInputStream
back again if you really to optimise when you can seek.
2
I think this kind of problem can be easily fixed by decorating the object.
In your case, you’re going to have your streams, using your stream interface, and a seeker stream decorator, which adds the seeking functionality you require. You can then decorate your streams with the seeking functionality whenever needed.
1