Java代码重构:多个instanceof运算符用法

时间:2014-09-25 14:35:36

标签: java refactoring polymorphism operators instanceof

考虑以下示例,其中类TextFileXmlFileHtmlFileShellScriptFile等等都是类SimpleFile的子类。我正在编写一个类FileOperations,它有一个方法可以根据类型搜索泛型文件的内容。

以下是代码示例:

public searchFile(SimpleFile targetFile, String searchStr) {
     if (targetPage instanceof HtmlFile) {
         // search html file
     }
     else if (targetPage instanceof TextFile) {
         // search text file
     }
     else if (targetPage instanceof XmlFile) {
         // search xml file
     }
     else if (targetPage instanceof ShellScriptFile) {
         // search shell file
     }   
     ...
}

这种结构对我来说很难闻。我知道这是多态性的最佳案例。但我无法控制File类或其子类。我无法写入它们。

还有另一种方法可以清理这个烂摊子吗?因为if-else结构会随着我添加对不同文件类型的支持而不断增加。

否则,如果我坚持使用这种结构,那么instanceof是Java中最快的运算符吗?它对绩效有何影响?

对于上述情况,使用getClass()isAssignableFrom()会更好吗?

感谢您的意见或建议!

4 个答案:

答案 0 :(得分:3)

首先我要说你的例子似乎并不坏。它有点冗长,并且可以说不像将它们分成不同的方法那样具有凝聚力,但它对我来说看起来很正常。我认为更简洁的方法可能是使用重载。我不能说速度上的差异,但从维护和可扩展性的立场来看,它将来会更容易处理。

public void searchFile(SimpleFile targetFile , String searchStr) {
     // SimpleFile generalized behavior.
     if (targetPage instanceof HtmlFile) searchFile((HtmlFile)targetFile, searchStr);
     else if (targetPage instanceof TextFile) searchFile((TextFile)targetFile, searchStr);
     else if (targetPage instanceof XmlFile) searchFile((XmlFile)targetFile, searchStr);
     else if (targetPage instanceof ShellScriptFile) searchFile((ShellScriptFile)targetFile, searchStr);
     else System.out.println("Subtype not recognised"); 
}
public void searchFile(HtmlFile targetFile , String searchStr) {
    // HtmlFile specific behavior
}
public void searchFile(TextFile targetFile , String searchStr) {
    // TextFile specific behavior
}
public void searchFile(XmlFile targetFile , String searchStr) {
    // XmlFile specific behavior
}
public void searchFile(ShellScriptFile targetFile , String searchStr) {
    // ShellScript specific behavior
}

如果是SimpleFile的新子类,它将默认为该方法的SimpleFile版本。如果在编译时未知类型(如注释中所示),则可以使用最通用的searchFile()方法来相应地检查和重新分发对象。

修改:关于多次使用instanceofconsensus appears to be that it's irrelevant, and that the use of modern instanceof is pretty fast anyway的性能影响的说明。

答案 1 :(得分:1)

如果您可以修改File及其子类,则可以尝试使用访问者模式。由于您不能,我建议您将类型测试开关语句合并到一个方法中,这样您只需要修改一个开关。

public Enum FileHandler {
   HTML(){
      public search(File file, String searchstr){ /* ... */}
      public prettyPrint(File file){ /* ... */}
   },
   XML(){ /* ... */};
   // ... end list of enum implementations

   public static FileHander get(File file){
      // Put your master switch statement here
      if (targetPage instanceof HtmlFile) {
         return HTML;
      }
      else if (targetPage instanceof XmlFile) {
         return XML;
      }
      // ...
   }
}

使用enum类的代码看起来像这样,避免了可怕的switch语句:

public searchFile(SimpleFile targetFile, String searchStr) {
   FileHandler.get(targetFile).search(targetFile, searchStr);
}

答案 2 :(得分:0)

您可以使用interpreter-design-pattern或责任链设计模式来解决此问题。这些模式似乎只是解决这个问题的完美方法。

解释器设计模式的示例,如果需要责任链设计模式的示例,请发表评论

客户端:

public Integer wordCountOnPage (Page samplePage) 
{
    ArrayList list = new ArrayList<Page>();
    list.add(new XmlPage());

    list.add(new HtmlPage());

    list.add(new JsonPage());

    for (int index = 0 ; index < list.size(); index ++)

    {
        Page eachPage = (Page) list.get(index); 
        if (eachPage.intercept(samplePage)){
            Integer i = eachPage.wordCountOnPage(samplePage);
        }

    }
    return 1;
}


public class XmlPage implements Page {

@Override
public Boolean intercept(Page page) {
    // TODO Auto-generated method stub
    return page instanceof XmlPage;
}

@Override
public Integer wordCountOnPage(Page page) {
    // TODO Auto-generated method stub
    return null;
}

}

public interface Page {

Boolean intercept(Page page);
Integer wordCountOnPage(Page page);
}

答案 3 :(得分:0)

我的方法是使用一个执行业务逻辑的方法创建一个接口FileSearcher。为每种文件类型创建此接口的一个实现。然后,创建一个注册表,将SimpleFile的子类映射到它们对应的FileSearcher实现。在您的搜索文件方法中,不是进行instanceof检查,而是在运行时查找匹配的FileSeacher实现并委托给它。

使用此实现时,如果存在HtmlFile等子类,则可能会遇到麻烦,因为您必须将HtmlFileSearcher映射到HtmlFile的所有子类。在这种情况下,将另一个方法添加到FileSearcher,名为canHandle(Class<SimpleFile> runtimeClass),允许FileSearcher实现发出他们理解的文件类的信号。在注册表中,不是在地图中查找,而是遍历所有已注册的FileSearchers