提问人:sagev 提问时间:11/17/2023 最后编辑:sagev 更新时间:11/17/2023 访问量:64
跟踪构建器在 Java 类型系统中添加的接口
Tracking interfaces added by a builder in the Java type system
问:
如果我有一个构建器类,有没有办法跟踪在类型级别添加了某些接口的事实?
例如,如果我有
var dinner = Noodling.build()
.name("Spaghetti") // Returns PastaBase & IName
.sauce("Marinara") // Returns PastaBase & ISauce, but I also want `& IName`
我想让这个编译
String name = dinner.getName();
但事实并非如此,因为没有保持这种类型。dinner
IName
这是目前我最接近这种模式的工作方式,但它仍然有这个问题。
public class Noodling {
public static PastaBase build() { return new Noodle(); }
public interface IName { String getName(); }
public interface ISauce { String getSauce(); }
public interface PastaBase {
public <T extends PastaBase & IName> T name();
public <T extends PastaBase & ISauce> T sauce();
}
public static class PastaImpl implements PastaBase, IName, ISauce {
@Override public <T extends PastaBase & IName> T name() { return (T) this; }
@Override public <T extends PastaBase & ISauce> T sauce() { return (T) this; }
@Override public String getName() { return name; }
@Override public String getSauce() { return sauce; }
}
}
如果我想要的超出了 Java 类型系统的可能性,我不会感到震惊,但它似乎非常接近!
答:
0赞
Jorn
11/17/2023
#1
不,这是不可能的。Java 没有动态类型。所有类型都必须在编译时已知,并且没有办法传递“你已经调用了方法,所以它现在也是一个”。name
IName
不过,也有解决方法。如果你的对象是可变的(、、等都返回相同的实例),你可以将调用结果分配给一个类型的变量,并调用它。或者,您可以为每个接口组合创建类,并根据调用的方法返回这些类。但这是很多代码,很可能没有太大的好处。name
sauce
name
IName
getName()
评论
0赞
sagev
11/17/2023
这就是我降落的地方。感觉类型系统只是一根头发短,因为它在编译时确实拥有所有信息(例如,它知道返回一个),但是如果没有构建一个可怕的接口树,就没有办法在这些调用之间携带这些信息。name()
IName
评论
Pasta