3 回答
TA贡献1852条经验 获得超1个赞
如果访问者具有通用返回类型,则访问的类不会与该类型耦合。
public interface Node {
<T> T accept(NodeVisitor<T> visitor);
}
public class ANode implements Node {
@Override
public <T> T accept(NodeVisitor<T> visitor) {
return visitor.visit(this);
}
}
public class BNode implements Node {
@Override
public <T> T accept(NodeVisitor<T> visitor) {
return visitor.visit(this);
}
}
public interface NodeVisitor<T> {
T visit(ANode aNode);
T visit(BNode bNode);
}
public class DtoNodeVisitor implements NodeVisitor<DTO> {
@Override
public DTO visit(ANode aNode) {
return new DTO(); //use ANode to build this.
}
@Override
public DTO visit(BNode bNode) {
return new DTO(); //use BNode to build.
}
}
ANode并且BNode对这里一无所知DTO。
TA贡献1785条经验 获得超4个赞
首先,在第 2 点中我不明白:
我的复合聚合必须实现访客
我想到的第一个问题是,为什么?您不能将访问者声明为接口,并将实现作为聚合的输入参数传递吗?
有没有办法在java中模拟重载方法的动态绑定(除了instanceof - 因为这可以解决我使用选项1的问题)?
是的,您可以使用反射来做到这一点,但真正的问题是,您想使用它们吗?
我认为答案取决于您需要管理多少案例以及它们发生变化的频率?
如果您有“可管理”数量的不同案例,则解决方案instanceof可以是一个很好的交易:
public Something myMethod(Entity entity){
if (entity instanceof AnEntity){
//do stuffs
else if (entity instanceof AnotherEntity){
//do something else
...
else {
throw new RuntimeException("Not managed " + entity.getClass().getName());
}
}
否则,当您有更多情况并希望将代码拆分为自己的方法时,您可以使用 Java 来完成MethodHandle,让我发布一个用法示例:
package virtualmethods;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
public class MyObject {
public String doStuffs(Object i) throws Throwable {
try {
final MethodType type = MethodType.methodType(String.class, i.getClass());
return (String) MethodHandles.lookup()
.findVirtual(getClass(), "doStuffs", type)
.invoke(this, i);
} catch (NoSuchMethodException e) {
throw new RuntimeException("Not managed " + i.getClass().getName(), e);
}
}
private String doStuffs(Integer i) {
return "You choose " + i;
}
private String doStuffs(Boolean b) {
return "You choose boolean " + b;
}
}
然后使用它:
package virtualmethods;
public class Main {
public static void main(String[] args) throws Throwable {
MyObject object = new MyObject();
System.out.println("Integer => " + object.doStuffs(5));
System.out.println("Boolean => " + object.doStuffs(true));
try {
System.out.println("String => " + object.doStuffs("something"));
}
catch (Throwable e) {
System.out.println("KABOOM");
e.printStackTrace();
}
}
}
获取an 的公共方法将查找以结果命名的方法并作为类中的输入(更多信息请参见此处)。 使用这种方式,您可以在运行时分派方法(使用重载是在编译时静态链接)。但这两种方法都存在一个问题,即您无法确定您将管理第一种情况和/或第二种情况中扩展/实现的所有类型,两种解决方案都有一个或一个来检查何时传递非托管类型到方法。MyObjectObjectdoStuffsStringi.getClass()MyObject
EntityObjectelsecatch
百分百确定您正在管理所有类型只能使用@jaco0646提出的解决方案来实现,据我所知,它强制您管理所有类型,否则它将无法编译。考虑到它需要的样板数量,我只会在抛出会RuntimeException导致业务问题时使用,并且我不能保证它不会使用适当的测试来抛出(除此之外,我发现它非常有趣)。
TA贡献1906条经验 获得超3个赞
听起来你把它过于复杂化了。如果您需要,typeof
那么您的聚合不会返回有效的域对象。它返回的域对象太通用。为了解决这个问题,您可以将聚合方法分为两种方法;一个返回 Child,另一个返回 Composite。然后,您的应用程序服务决定调用哪一个(如果可能)。
如果由于某种原因您需要聚合返回通用对象,我会重新考虑您选择的设计。
另一个“黑客”是简单地在域对象上放置一个属性来指示它是复合对象还是子对象。我假设聚合会知道它是否是并且能够准确地填充该属性。
添加回答
举报