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。然后,您的應用程序服務決定調用哪一個(如果可能)。
如果由于某種原因您需要聚合返回通用對象,我會重新考慮您選擇的設計。
另一個“黑客”是簡單地在域對象上放置一個屬性來指示它是復合對象還是子對象。我假設聚合會知道它是否是并且能夠準確地填充該屬性。
添加回答
舉報