Reputation: 330
Since I am refactoring my code right now, I am trying to first sort out possible code duplicates. As a posible duplicate I see the 2 methods which basically read files: One from FTP and another from local filestructures. The problem is, that they of course use different classes to achieve the same things. The variable directoryListing is the tricky one.
readLogs(boolean useFTP){
// directory Listing of course needs to be of a different type here or not being declared at all
File[] directoryListing;
File dir = Settings.getInputfolder();
if(useFTP){
// ftp implementation
client = new FTPClient();
client.connect(Settings.getFtpHost());
client.enterLocalPassiveMode();
client.login(Settings.getFtpLoginname(), Settings.getFtpPassword());
client.setFileType(FTPClient.BINARY_FILE_TYPE);
//directoryListing should be of type FTPFile[] here
directoryListing = client.listFiles(Settings.getInputfolder().toString());
else{
//directoryListing should be of type File[] in this case
directoryListing = dir.listFiles();
}
if (directoryListing == null) {
log.error("Input-folder not found:" + dir.getAbsolutePath());
}
//I want to be able to iterate - here myFolder might be of type File oder FTPFile
for (Object myFolder : directoryListing) {
...
...
}
}
The only methods I am using later on in the code have the exact same signatures on both File and FTPFile:
getName()
isFile()
isDirectory()
listFiles()
I have used reflections for those e.g.
Method getFolderNameMethod = myFolder.getClass().getMethod("getName");
String name = (String) getFolderNameMethod.invoke(myFolder);
In what way can I achieve a somewhat dynamic declaration of the directoryListing variable?
Thank you very much for your time and advice in advance! :D
Upvotes: 0
Views: 81
Reputation: 8075
Use Strategy and Adapter pattern:
First define the common interface
interface VirtualFile {
/*
getName()
isFile()
isDirectory()
listFiles()
*/
}
then create two adapter (one for File, one for FTPFile)
class FileAdapter implements VirtualFile {
// delegates every method to the wrapped file
}
class FTPFileAdapter implements VirtualFile {
// delegates every method to the wrapped ftp file
}
Then refactor readLogs
:
readLogs(FileStrategy fileOrFtp){
List<VirtualFile> directoryListing = fileOrFtp.listDirectory();
for (VirtualFile myFolder : directoryListing) {
...
...
}
}
interface FileStrategy {
List<VirtualFile> listDirectory();
}
class FTPFileStrategy implements FileStrategy {
// implement useFTP case (settings should be passed to the constructor
// wrap each resulting FTPFile into a FTPFileAdapter
}
class LocalFileStrategy implements FileStrategy {
// implement !useFTP case (settings, e.g. root folder should be passed to the constructor
// wrap each resulting File into a FileAdapter
}
This keeps all concerns separated and additionally: - no ifs any more - no casting - no reflection - shorter methods/classes
Upvotes: 1
Reputation: 11267
I have used apache-commons-vfs in the past:
http://commons.apache.org/proper/commons-vfs/
If you don't want to ad a lib, you could create an interface and 2 implementations of it, but VFS will give you more supported filesystems and probably be easier to maintain in the long run.
I'm sure there are others, but I've never needed anything other than the apache one so I can't speak to them.
Edit:
Based on your comment, I'd crate a factory, something like:
public class FSFactory{
public static IFSInteface getInterfaceFor(FSType t){
if(FSType.FTP.equals(t)){
return new FtpFileGetter();
} else if (FSType.LOCAL.equals(t)){
return new FSFileGetter();
}
}
}
The code is not tested, but this is how I handle stuff like this.
Upvotes: 1