如何在java中实现更改输出类型的承诺
我试图用java实现一个简单的promise系统。我这样做是为了特殊目的,所以请不要推荐任何图书馆 当我尝试实现一个如何在java中实现更改输出类型的承诺,java,promise,Java,Promise,我试图用java实现一个简单的promise系统。我这样做是为了特殊目的,所以请不要推荐任何图书馆 当我尝试实现一个thenApply()方法时,我遇到了一个问题,该方法将函数作为参数,类似于have,因此返回另一种类型的承诺 承诺界面: public interface Promise<T> { Promise<T> then(Consumer<T> handler); <U> Promise<U> thenAppl
thenApply()
方法时,我遇到了一个问题,该方法将函数作为参数,类似于have,因此返回另一种类型的承诺
承诺界面:
public interface Promise<T> {
Promise<T> then(Consumer<T> handler);
<U> Promise<U> thenApply(Function<T, U> handler);
}
公共接口承诺{
然后承诺(消费者处理人);
承诺然后应用(函数处理程序);
}
我迄今为止的执行情况:
public class PromiseImpl<T> implements Promise<T> {
private List<Consumer<T>> resultHandlers = new ArrayList<>();
public PromiseImpl(CompletableFuture<T> future) {
future.thenAccept(this::doWork);
}
@Override
public Promise<T> then(Consumer<T> handler) {
resultHandlers.add(handler);
return this;
}
@Override
public <U> Promise<U> thenApply(Function<T, U> handler) {
// How to implement here??? I don't have the result yet
handler.apply(?);
}
private void onResult(T result) {
for (Consumer<T> handler : resultHandlers) {
handler.accept(result);
}
}
private Object doWork(T result) {
onResult(result);
return null;
}
}
公共类PromiseImpl实现承诺{
private List resultHandlers=new ArrayList();
公共承诺(可完成的未来){
然后接受(这个::工作);
}
@凌驾
公众承诺(消费者处理人){
添加(处理程序);
归还这个;
}
@凌驾
公共承诺然后应用(函数处理程序){
//如何在这里实施???我还没有结果
处理程序。应用(?);
}
私有void onResult(T result){
for(使用者处理程序:ResultHandler){
接受(结果);
}
}
私有对象工作(T结果){
onResult(result);
返回null;
}
}
问题是我不知道我最初在thenApply()
方法中的结果,因此我无法调用我的处理程序。另外,我不想调用future.get()
,因为这个方法是阻塞的
我如何才能做到这一点?您可以返回一些匿名类,该类扩展PromiseImpl并重写onResult,以便处理程序接受应用映射器函数的结果。不要忘记调用父onResult,以便调用父处理程序 真正的问题在于你的
Promise
类型的设计。它持有一组回调,所有回调都将在完成时调用。这是一个基本问题(围绕然后apply
函数的返回类型限制通用功能)。这可以通过更改Promise
实现来解决,即在注册处理程序时返回new
Promise,而不是返回This
,这样每个Promise对象都将有自己的处理程序来调用
除了解决这个问题之外,它还是一个更好的函数式编程设计,因为您可以使您的Promise
对象不可变
我会将界面更改为:
interface Promise<T> {
<U> Promise<U> thenApply(Function<T, U> handler);
Promise<Void> thenAccept(Consumer<T> consumer);
}
使用它可以非常简单:
Promise<String> stringPromise = new PromiseImpl<>(new CompletableFuture<String>());
Promise<Long> longPromise = stringPromise.thenApply(str -> Long.valueOf(str.length()));
Promise<Void> voidPromise = stringPromise.thenAccept(str -> System.out.println(str));
并通过以下方式实施:
public T get() {
//try-catch
return this.future.get();
}
注意:这看起来越来越像是对CompletableFuture
的复制,这就提出了一个问题:为什么要这样做。但是假设在这个接口中会有其他类似于Promise的方法,那么这个方法将包装未来的API
如果需要将同一个
Promise
对象与回调列表一起使用,则别无选择,只能使用函数
具体类型参数对Promise
接口进行参数化:
public interface Promise<T, U>
公共接口承诺
如果您想保持类的其余部分不变并只实现
然后应用
方法,U
将不能成为然后
或然后应用
上的方法泛型参数,您必须创建一个新的可完成的未来
,因为这是您当前构建新的承诺的唯一方法:
@Override
public <U> Promise<U> thenApply(Function<T, U> handler) {
CompletableFuture<U> downstream = new CompletableFuture<>();
this.then(t -> downstream.complete(handler.apply(t)));
return new PromiseImpl<>(downstream);
}
但是,如果您想在CompletableFuture
之上实现自己的API,您真正应该做的是使用decorator模式,并将CompletableFuture
实例包装为PromiseImpl
中的私有变量,因为类型可能不兼容,我认为此解决方案不起作用。考虑<代码>字符串< /代码>和<代码>整数< /代码>类型。如果你认为我错了,请提供一个代码示例。你没有指定你希望然后应用实际执行的操作…@Michael与然后方法相同,但是使用另一种返回类型,你打算如何获取返回值<代码>承诺
没有这样做的方法。但是然后接受
是否应该返回一个承诺
?对于承诺
,我能实际做些什么?为什么不仅仅是void
?@Michael我为“如何检索值”编辑了这篇文章,但这本质上是关于使用未来实例的<除非Promise
接口中增加了更多的方法,例如检查状态,即使没有返回值,否则code>Promise
也不会有用(这将类似于<代码>完整的未来< /代码>。我假设问题中的接口版本被简化了。否则,我真的不明白为什么一个人不能只使用<代码>完整的未来<代码>。@ EnnistkKiWele认为我不是java 8,这意味着我不能使用<代码>完整的未来< /代码>。我只是使用了<代码>pletableFuture
作为一种简单的方法来表明存在某种延迟操作。我的错,我应该在问题中提到这一点。@flash绝对,你可以有很多很好的理由这样做,而不是争论这一点。但是,在Java8之前,我们的Future
接口更差,实现了FutureTask
它。我想说的是,我们应该假设你有很好的理由来实现这个…:-)@ErnestKiwele抱歉,今天不是我最好的一天。我仍然被卡住了。未来任务的实现会发生什么变化?它确实有一个get
方法,但这会阻止然后apply
方法,对吗?
public interface Promise<T, U>
@Override
public <U> Promise<U> thenApply(Function<T, U> handler) {
CompletableFuture<U> downstream = new CompletableFuture<>();
this.then(t -> downstream.complete(handler.apply(t)));
return new PromiseImpl<>(downstream);
}
@Override
public <U> Promise<U> thenApply(Function<T, U> handler) {
PromiseImpl result = new PromiseImpl();
this.then(t -> result.doWork(handler.apply(t)));
return result;
}