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你甚至不需要改变你的设计...... –

相关问题