2014-09-25 3 views
1

다음과 같은 예를 생각해 용도 어디 클래스 TextFile, XmlFile, HtmlFile, ShellScriptFile, 등등, 클래스 SimpleFile의 모든 서브 클래스이다. 그 유형에 따라 일반 파일의 내용을 검색하는 메소드가있는 클래스 FileOperations을 쓰고 있습니다.자바 코드 리팩토링 : 여러 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

속도가이 상황 –

+0

에 전혀 관심입니다 File 클래스 또는 그 서브 클래스에 대한 제어가 없다 " –

+0

나는 명시 했으므로 수퍼 클래스 나 서브 클래스에 쓸 수 없다. 나는 그들을 통제 할 권한이 없다. – Chiseled

답변

3

먼저 나는 당신의 예가 전혀 나빠 보이지 않는다고 말할 것입니다. 그것은 약간 장황하고, 다른 방법으로 그것들을 분리하는 것처럼 응집되어서는 안되지만, 그것은 나에게 상당히 정상적으로 보입니다. 나는 깔끔한 접근법이 대신에 과부하를 사용하는 것이라고 생각한다. 나는 속도의 차이에 대해 말할 수는 없지만, 유지 보수와 확장 성 관점에서 미래에 다루기가 더 쉬울 것입니다. SimpleFile의 새로운 서브 클래스의 이벤트에서

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 버전으로 기본 설정됩니다. 형식이 컴파일 타임에 알려지지 않은 경우 (의견에서 제기 된 것처럼) 가장 일반적인 searchFile() 메서드를 사용하여 그에 따라 개체를 확인하고 재배포 할 수 있습니다.

편집 : instanceof을 여러 번 사용하여 성능에 미치는 영향에 대한 참고로 consensus appears to be that it's irrelevant, and that the use of modern instanceof is pretty fast anyway.

+1

형식이 컴파일 타임에 알려지면 작동합니다. –

+0

나는 동의하지만 여기서는 그렇지 않다. – Chiseled

+0

@OliverCharlesworth - True. 나는 그들이 여전히 런타임을 위해'instanceof'로 돌아 가야 할 것이라고 생각한다. 이는 객체를 적절하게 재배포하기 위해 일반화 된'SimpleFile' 메소드의 목적 일 수 있습니다. –

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

0

내 접근 방식은 비즈니스 로직을 수행하는 단일 메소드로 인터페이스 FileSearcher을 작성하는 것입니다. 파일 유형별로이 인터페이스의 구현을 하나 만듭니다. 그런 다음 SimpleFile의 서브 클래스를 해당 구현 FileSearcher에 맵핑하는 레지스트리를 작성하십시오. 검색 파일 방법에서 instanceof 검사를 수행하는 대신 런타임에 일치하는 FileSeacher 구현을 찾아 위임하십시오.

HtmlFile 등 모든 하위 클래스에 HtmlFileSearcher을 매핑해야하므로이 구현에서는 HtmlFile 등의 하위 클래스가있을 때 문제가 발생할 수 있습니다. 이 경우 에 canHandle(Class<SimpleFile> runtimeClass)이라는 또 다른 메서드를 추가하면 구현에서 해당 클래스가 이해하는 파일 클래스를 알릴 수 있습니다. 레지스트리에서지도에서 찾아보기보다는 모든 등록 된 FileSearchers을 걸어보십시오.

1

File 및 그 하위 클래스를 수정할 수있는 경우 Visitor 패턴을 사용해 볼 수 있습니다. 할 수 없으므로 유형 테스트 스위치 구문을 단일 메소드로 통합하여 스위치 하나만 ​​수정하면됩니다.

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

그리고 지칠대로 지친 스위치 문을 피하고, 다음과 같이 보일 것이다 열거 클래스를 사용하도록 코드 : 나는 "같은데요 때문에

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