2014-09-25 447 views
1

考慮下面的例子,其中類TextFileXmlFileHtmlFileShellScriptFile,等等,是類SimpleFile的所有子類。我正在編寫一個類FileOperations,它有一種方法,根據類型搜索通用文件的內容。Java代碼重構:多個instanceof操作用法

下面是一個代碼示例:

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()會更好嗎?

我感謝您的意見或建議!

+0

速度是在這種情況下 – 2014-09-25 14:41:01

+0

沒有關注,因爲,我猜「我無法控制文件類或其子類「 – 2014-09-25 14:42:26

+0

,正如我所說的,我無法寫入超類或子類。我無法控制他們。 – Chiseled 2014-09-25 14:43:13

回答

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版本的方法。如果在編譯時未知類型(如註釋中提到的那樣),則最常用的方法可用於相應地檢查和重新分發對象。

編輯:作爲性能影響的說明,多次使用instanceof,consensus appears to be that it's irrelevant, and that the use of modern instanceof is pretty fast anyway

+1

如果在編譯時已知類型,這將起作用。 – 2014-09-25 14:44:04

+0

我同意,但情況並非如此 – Chiseled 2014-09-25 14:46:13

+0

@OliverCharlesworth - 確實如此。我想他們仍然必須回退'instanceof'來運行。這可能是廣義的'SimpleFile'方法的目的,以恰當地重新分配對象。 – 2014-09-25 14:47:03

0

你可以使用interpreter-design-pattern或chain-of-responsibility-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); 
} 
+0

不幸的是我不能編輯基類或派生類。謝謝 !! – Chiseled 2014-09-27 00:35:11

0

我的方法是用一個執行業務邏輯的方法創建一個接口FileSearcher。爲每個文件類型創建一個此接口的實現。然後,創建一個註冊表,將SimpleFile的子類映射到FileSearcher的相應實現。在您的搜索文件方法中,而不是執行instanceof檢查,在運行時查找匹配的FileSeacher實現並委託給它。

有了這個實現,當存在HtmlFile等的子類時,您可能會遇到麻煩,因爲您必須將HtmlFileSearcher映射到HtmlFile的所有子類。在這種情況下,將另一種方法添加到FileSearcher,名爲canHandle(Class<SimpleFile> runtimeClass),允許FileSearcher實現發出他們瞭解的文件類的信號。在註冊表中,不要在地圖上查找,而是遍歷所有註冊的FileSearchers

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; 
     } 
     // ... 
    } 
} 

和代碼下載到使用枚舉類會是這個樣子,避免了可怕的switch語句:

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