1

我的出發點的方法如下:
- 我有一個方法,變換,我重載不同的行爲取決於所傳入的參數類型(見變換(A a1,A a2)和變換(A a1,B b)在我的示例中)
- 所有這些參數實現相同的接口,X調用重載的所有參數實現相同的接口

我想在各種對象上應用該變換方法全部實現X界面。

我想到的是實現變換(X x1,X x2),它在應用變換的相關變體之前檢查每個對象的實例。

儘管它有效,但代碼看起來很難看,我也擔心評估這些各種instanceof和cast的性能開銷。這種轉變是我在Java中可以做到的最好的轉變嗎?還是有一種更優雅和/或有效的方式來實現相同的行爲?

以下是一個簡單的工作示例,打印出BA。我正在尋找如何改進代碼的例子。在我真正的代碼中,我自然有更多的'transform'實現,而且沒有一個像下面那樣微不足道。

public class A implements X { 
} 

public class B implements X { 
} 

interface X { 
} 

public A transform(A a1, A a2) { 
    System.out.print("A"); 
    return a2; 
} 

public A transform(A a1, B b) { 
    System.out.print("B"); 
    return a1; 
} 

// Isn't there something better than the code below??? 
public X transform(X x1, X x2) { 
    if ((x1 instanceof A) && (x2 instanceof A)) { 
    return transform((A) x1, (A) x2); 
    } else if ((x1 instanceof A) && (x2 instanceof B)) { 
    return transform((A) x1, (B) x2); 
    } else { 
    throw new RuntimeException("Transform not implemented for " 
      + x1.getClass() + "," + x2.getClass()); 
    } 
} 

@Test 
public void trivial() { 
    X x1 = new A(); 
    X x2 = new B(); 
    X result = transform(x1, x2); 
    transform(x1, result); 
} 
+0

我還發現了下面的帖子相關:http://sites.google.com/site/steveyegge2/when-polymorphism-failures – double07

+1

性能應該不用擔心 - 除非你打算非常頻繁地運行這段代碼。先讓它工作,然後再優化。 – Bombe

回答

5

看看在Visitor pattern爲出發點。

如果您的層次結構發生了很大變化,訪問者模式將對變化進行分散。在這種情況下,也請看acyclic visitor

的代碼看起來是這樣的:

public interface X { 
    void accept(XVisitor v); 
} 

public interface XVisitor { 
    void visit(A a); 
    void visit(B b); 
} 

public class A implements X { 
    public void accept(XVisitor v) { 
    v.visit(this); 
    } 
} 

public class B implements X { 
    public void accept(XVisitor v) { 
    v.visit(this); 
    } 
} 

然後你的算法進入這個類:

public class XTransformerVisitor implements XVisitor { 
    private X result; 
    private A first; 
    public void visit(A a) { 
    if (first == null) first = a; 
    else result = a; 
    } 
    public void visit(B b) { 
    if (first == null) throw new RuntimeException(); 
    result = first; 
    } 
    public X transform(X x1, X x2) { 
    x1.accept(this); 
    x2.accept(this); 
    return result; 
    } 
} 
+0

感謝您的回答。我的層次結構不會改變。我更關心代碼的可讀性以及調用instanceof和執行轉換可能的性能影響。在閱讀你指出的例子之後,我仍然不清楚訪問者模式是否對我來說是一個更好的折衷。會嗎? – double07

+0

也許,這是一個開始......我會發布一些代碼,你將成爲法官。 –

+0

好的,我賣了。並感謝這個例子:使它更具體。 – double07

3

你正在尋找的術語多分派,這是在多個參數類型中多態的虛擬函數的泛化。大多數編程語言,包括Java和C++,都不支持多次調度,因此需要某種駭客來模擬它。一種選擇是讓代碼如上所述,另一種方法是使用like this。一個常見的解決方案是使用一個稱爲visitor pattern的成語,它可以幫助抽象出複雜性。

+0

+1提及_multiple dispatch_ –

0

經過一番研究,我發現了反思的概念。我認爲這比訪問者模式簡單得多,至少要解決這裏的具體問題。

我上面的原代碼,可以保持完全相同,惱人的變換方法(X X1,X×2)簡單地變爲:

public X transform(X x1, X x2) { 
    Method m; 
    try { 
    m = getClass().getMethod("transform", 
      new Class[]{x1.getClass(), x2.getClass()}); 
    return (X) m.invoke(this, new Object[]{x1, x2}); 
    } catch (Exception e) { 
    throw new RuntimeException("Transform not implemented for " 
     + x1.getClass() + "," + x2.getClass()); 
    } 
} 

優點:
- 擺脫了嵌套instanceof測試和鑄造我的曾在我原來的職位
- 無需實現一個accept方法,所有的操作數必須由雙調度/訪問者模式的方法工具帶來

+0

+1你甚至不需要改變你的設計...... –

相關問題