2013-12-19 16 views
-1

我對此從單個接口派生一些類的數據模型,如:基於使用instanceof或reflection的類的類型的切換方法?

public interface Foo extends Visitable {} 

public class BarA implements Foo { 
    void accept(Visitor visitor) { 
     visitor.visit(this); 
    } 
} 

public class BarB implements Foo { 
    void accept(Visitor visitor) { 
     visitor.visit(this); 
    } 
} 

... 

也有一個Visitor具有用於做一些與數據模型中的類的一些方法:

public class ModelVisitor implements Visitor { 

    String visit(Foo foo) { 
      // ... 
    } 

    String visit(BarA bar) { 
     // ... 
    } 

    String visit(BarB bar) { 
     // ... 
    } 

    // ... 
} 

說,我得到了Foo類型的集合,遍歷它們的元素,並調用visit()

void run(List<Foo> fooList) { 
    for(Foo foo : fooList) { 
     // here is the question 
     foo.visit(); 
    } 
} 

我如何決定調用哪個visit()方法,因爲它們都是foo的所有子類?我有兩個可能的想法:

  1. 使用instanceof和轉換爲正確的類型,但我想避免,因爲我會在很多ifelse if條件結束。
  2. 我的另一種方法是使用反射。該應用程序將在Java7中運行,這就是爲什麼我可以在switch-case語句中使用字符串比較的原因。

例如:

String visit(List<Foo> fooList) { 
    for(Foo foo : fooList) { 
    switch(foo.getClass().getName()) { 
     case "BarA": 
      visit((BarA) foo); 
      break; 
     case "BarB": 
      visit((BarB) foo); 
      break; 
     // ... 
     } 
    } 
} 

在我看來,第二種方法看起來比使用instanceof清潔,但反射被稱爲慢。我的JVM知識不太好,但我認爲instanceof也將使用反射來獲取對象的類型,所以兩種解決方案之間沒有真正的性能差異。

你會使用什麼或有其他方法來解決這個問題?

+1

你應該改寫你的問題,如「如何切換基於類型的訪問者方法」,或者簡單地「訪問者模式如何工作」 –

回答

0

在訪問者模式調用

foo.accept(visitor); 

具體Foo對象,然後決定哪些Visitor方法調用。您不需要instanceof

例如,我刪除了一些接口,使代碼更小。

public class Main { 

    public static void main(String[] args) { 
     Bar bar1 = new BarA(); 
     Bar bar2 = new BarB(); 

     Visitor visitor = new Visitor(); 
     bar1.accept(visitor); 
     bar2.accept(visitor); 
    } 

    public static class Bar { 
     public void accept(Visitor visitor) { 
      visitor.visit(this); 
     } 
    } 

    public static class BarB extends Bar { 
     public void accept(Visitor visitor) { 
      visitor.visit(this); 
     } 
    } 

    public static class BarA extends Bar { 
     public void accept(Visitor visitor) { 
      visitor.visit(this); 
     } 
    } 

    public static class Visitor { 

     public void visit(Bar bar) { 
      System.out.println("visited: Bar"); 
     } 

     public void visit(BarA bar) { 
      System.out.println("visited: BarA"); 
     } 

     public void visit(BarB bar) { 
      System.out.println("visited: BarB"); 
     } 

    } 

} 

運行示例將輸出

visited: BarA 
visited: BarB 
+0

這是正確的,但不回答我的問題當你有一個'列表'fe,其中'BarA'和'BarB'是'Bar'的子類。 –

+0

@ klingt.net它和'BarA'和'BarB'實現'Foo'一樣,只是你必須在'Bar'中實現'accept(Visitor)'。但是,當然,你不能僅在Bar類中實現'acceptVisitor()',而只需擴展'Bar'。這不是訪客模式的內容。訪問者模式基於多態。請參閱http://en.wikipedia.org/wiki/Visitor_pattern –

+0

@ klingt.net我更新了我的答案,並在評論中提到了您的酒吧示例。 –

0

沒有必要爲任一那些只要富陣列中每個對象已經與其明確的構造函數創建。我覺得代碼更好地解釋道:

使用你的代碼應該創建富列表這樣的客戶:

ArrayList<Foo> list = new ArrayList<Foo>(); 
list.add(new BarA()); 
list.add(new BarB()); 
... 

這就是你需要的。當方法visit()被調用並通過「列表」中的一個對象時,它將通過適當的方法。這是多晶現象的魔力。

如果你想確保,只是繼續前進,用打印出清單:

for(Foo f : list) 
System.out.println(f); 

類的名字將被打印出來,你會看到每個對象的引用去它的類而不是Foo:[email protected]

儘管如此,我認爲你仍然沒有訪客模式的概念。