(Cross-post programmers.stackexchange) I am trying to make use of SOLID principles for the first time. I am re-factoring a File class that stores file information and makes file operations available. This class is then inherited to specific file types to make available methods for that type.
I have started with SRP and have tried to make a FileWriter
and FileReader
abstract class to read and write from different resources. Some include:
SOAP
, REST
??).I am happy to say that the file data is handled by a byte array, but I am not sure how to handle the file path/uid for a resource.
Here is what I have...
public abstract class EFileReader
{
event EventHandler<IEFileEventArgs> ReadThreadedComplete;
public abstract byte[] Read(object source);
public abstract async Task<byte[]> ReadAsync(object source);
public abstract void ReadThreaded(object source);
protected virtual void OnFileRead(IEFileEventArgs e)
{
EventHandler<IEFileEventArgs> handler = this.ReadThreadedComplete;
if (handler != null)
{
handler(this, e);
}
}
}
I could cast the object as the required type in implementation. Alternatively it could be a generic type somehow specified in implementation.
public abstract class EFileReader<T>
{
event EventHandler<IEFileEventArgs> ReadThreadedComplete;
public abstract byte[] Read(T source);
public abstract async Task<byte[]> ReadAsync(T source);
public abstract void ReadThreaded(T source);
protected virtual void OnFileRead(IEFileEventArgs e)
{
EventHandler<IEFileEventArgs> handler = this.ReadThreadedComplete;
if (handler != null)
{
handler(this, e);
}
}
}
I could define or constrain T
in the implementation.
...Or maybe there is some abstraction of the source I can write to accommodate the various possible use cases.
I guess I could make it take an abstract FileResource
class that exposes a stream.
What is the best way to approach this?
I think you're on the right track with creating a new type, but I'd call it FileIdentifier. It would not necessarily "expose a stream" itself, instead it would be used with a FileStorage class, like
abstract class FileStorage
{
public abstract Stream GetStream(FileIdentifier id);
}
The FileReader class might not need to be abstract anymore - instead its constructor would require an instance of a FileStorage-derived class, which would own the details of getting a stream from a file:
class FileReader
{
FileReader(DiskFileStorage storage)..
override byte[] Read(FileIdentifier id)
{
Stream stream = this.storage.GetStream(id);
return stream.Read....
}
}
You could have DiskFileStorage, NetworkFileStorage, DatabaseFileStorage, etc, with corresponding FileIdentifer-derived classes. DiskFileIdentifier would just wrap a file path string, NetworkFileIdentifier might wrap a URL, DatabaseFileIdentifier might wrap a username, password, table and primary key, and so on.