【问题标题】:Is there a way to assign the Class in Java at Runtime?有没有办法在运行时分配 Java 中的类?
【发布时间】:2015-12-07 23:06:36
【问题描述】:

因为我现在正在重构我的代码,所以我试图首先整理出可能的代码重复。 作为一个可能的副本,我看到了两种基本上读取文件的方法:一种来自 FTP,另一种来自本地文件结构。问题是,他们当然使用不同的类来实现相同的目标。变量 directoryListing 是一个棘手的问题。

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) {
    ...
    ...
    }
}

我稍后在代码中使用的唯一方法在 File 和 FTPFile 上具有完全相同的签名:
获取名称()
isFile()
isDirectory()
列表文件()
我已经为那些使用了反射,例如

Method getFolderNameMethod = myFolder.getClass().getMethod("getName");
String name = (String) getFolderNameMethod.invoke(myFolder);

我可以通过什么方式实现 directoryListing 变量的某种动态声明?

非常感谢您提前提供的时间和建议! :D

【问题讨论】:

  • 这里可以使用泛型吗?我的意思是创建一个遍历列表并进行处理的类,但它是一个通用类,现在您当然知道当 useFTP 为 true 时,它​​正在获取 FTPFile 实例的类型,而在其他情况下,它正在获取 File 实例,这可能简化处理。
  • @BilboBaggins 据我所知,在不知道列表类型(FTPFile[] 或 File[])的情况下,您无法遍历列表,因此在获取之前我会失败。不过是个好主意……
  • 谢谢 :) 我也在考虑获取目录列表的策略模式,即如果“useFTP”为真,则调用您已实现 FTPFile 相关内容的类的实例,否则调用和为 File 使用另一个实例 :)
  • @BilboBaggins 这样做会为 FTP 和本地 2 种情况产生大量重复代码:/

标签: java class dynamic reflection


【解决方案1】:

使用策略和适配器模式:

先定义通用接口

interface VirtualFile {
  /*
  getName()
  isFile()
  isDirectory()
  listFiles()
  */
}

然后创建两个适配器(一个用于文件,一个用于 FTPFile)

class FileAdapter implements VirtualFile {
  // delegates every method to the wrapped file
}

class FTPFileAdapter implements VirtualFile {
  // delegates every method to the wrapped ftp file
}

然后重构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
}

这将所有关注点分开,另外: - 没有如果 - 没有铸造 - 没有反射 - 更短的方法/类

【讨论】:

    【解决方案2】:

    我过去使用过 apache-commons-vfs:

    http://commons.apache.org/proper/commons-vfs/

    如果你不想添加一个库,你可以创建一个接口和它的 2 个实现,但是 VFS 会为你提供更多受支持的文件系统,并且从长远来看可能更容易维护。

    我确定还有其他人,但我从来不需要除了 apache 以外的任何东西,所以我无法与他们交谈。

    编辑:

    根据您的评论,我会创建一个工厂,例如:

    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();
         }
      }
    }
    

    代码未经测试,但这是我处理此类事情的方式。

    【讨论】:

    • 嗯,是的,我现在确实有 2 个代码实现。我真正想做的是“在运行时”确定 directoryListing 是否应该是 FTPFile[] 或 File[] 类型,从而从长远来看减少重复代码。谢谢你的图书馆提示。我会在下一个项目中尝试一下:)
    • 非常感谢您的回复。您能否详细说明如何使用 Factory 来设置 directoryListing 类?例如我应该如何从我的代码中调用它?或者一旦我拥有 IFSInterface 该怎么办?
    • 我会使用 listFiles() 方法将 if 的每个分支分解为单独的类,并使用工厂而不是代码中的 if/else 来获取实例。
    猜你喜欢
    • 1970-01-01
    • 2011-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-03
    • 1970-01-01
    • 1970-01-01
    • 2020-09-02
    相关资源
    最近更新 更多