异步http请求的解耦设计 [英] decoupled design for async http request

查看:107
本文介绍了异步http请求的解耦设计的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要写的是视图->控制器->模型->客户端->抽象的HttpRequestSender关系,因此当我使用其他平台(android-volley,Fx-SpringRest)时,可以替换HttpRequestSender 。因为在android上,我需要使用一个非主线程来执行HttpRequest,所以我的解决方案是使用从控制器向下发送的回调链,以启用所需的异步行为。

What i am trying to write is a view-> controller -> model -> client -> HttpRequestSender relationship that is abstract, so i can replace the HttpRequestSender when i am using different platform (android-volley, Fx-SpringRest). since on android i need to use a-non main thread to preform the HttpRequest, my solution was to use a callback that is sent from the controller down throw the chain to enable the asynchronous behavior needed.

我的问题是,尽管这是一个可行的解决方案,但代码却变得非常难于跟踪

My issue is that all though it is a working solution, the code becomes highly hard to follow.

所以这是一种简单的方法类似于 registerDevice(String name)-如下所示:

So that a simple method like registerDevice(String name) - as seen below:

public class DeviceRegModel {

    DeviceClient client;

    DeviceInfoMgr deviceInfoMgr;

    public void registerDevice(String name) throws DeviceNameTakenException {
        checkIfNameTaken(name);

        Device device = client.createDevice().getBody();

        device.setName(name);

        client.updateDevice(device);

        deviceInfoMgr.set(name);
    }

    private void checkIfNameTaken(String name) throws DeviceNameTakenException {
        for(Device dev : client.getAllDevices()) {
            if(dev.getName() == name) {
                throw new DeviceNameTakenException();
            }
        }
    }

成为:

public class DeviceRegModel implements IModel {



DeviceClient client;

    DeviceInfoMgr deviceInfoMgr;


    public void registerDevice(String name, HttpCallback callback)   {
        ResponseCommand onOk = (res) -> checkIfNameTaken(name, res, callback);
        HttpFailCommands onFail = callback.getOnFailCmds();

        client.getAllDevices(HttpCallback.build(onOk, onFail));

    }

    private void checkIfNameTaken(String name, IResponse res, HttpCallback callback)  {
        for(Device dev : res.<Device[]>getBody()) {
            if(dev.getName() == name) {
                ExceptionCommand failCmd = callback.getOnFailCmds().getInternalFailCmd();
                failCmd.execute(new DeviceNameTakenException());
            }
        }
        createDevice(name,callback);
    }

    private void createDevice(String name, HttpCallback callback) {
        ResponseCommand onOk = (res) -> setNameLocally(name, res, callback);
        HttpFailCommands onFail = callback.getOnFailCmds();

        client.createDevice(HttpCallback.build(onOk, onFail));
    }

    private void setNameLocally(String name, IResponse res, HttpCallback callback) {
        Device device = res.<Device>getBody();
        device.setName(name);

        ResponseCommand onOk = (cmdRes) -> updateServer(name, cmdRes, callback);
        HttpFailCommands onFail = callback.getOnFailCmds();

        client.updateDevice(device, HttpCallback.build(onOk, onFail));
    }

    private void updateServer(String name, IResponse res, HttpCallback callback) {
        deviceInfoMgr.set(name);
        callback.getOnOkCmd().execute(res);
    }
}

我想弄清楚自己是否在正确的路径(使用第二个版本)还是应该更改我的设计?

I am trying to figure out if i am on the correct path here (with the second version) or should change my design?

推荐答案

何时要组成可能涉及许多异步步骤的计算,没有任何真正好的选择可以让您编写超干净的代码。

When you want to compose computations that may involve a lot of asynchronous steps, there aren't any really good options that will let you write super-clean code.

可以使用em>-事件驱动的设计,连续传递,monad等,monad是现代的选择,因为它们使您可以编写具有与等效同步代码相同基本结构的异步代码。它仍然不是很漂亮的代码,但是至少它是由相同的功能块构建的。

Of the options that are available -- event-driven design, continuation passing, monads, etc., monads are the modern choice, because they let you write asynchronous code that has the same basic structure as the equivalent synchronous code. It's still won't be very pretty code, but at least it's built of the same functional blocks.

在JavaScript中,异步monad是Promise,而在Java中,则是CompletionStage / CompletableFuture。这就是您的类以这种样式显示的样子(我假设对 client 的所有调用都是异步的,并返回CompletionStage):

In JavaScript the asynchronous monad is Promise, and in Java it's CompletionStage/CompletableFuture. This is what your class looks like in that style (I'm assuming all the calls to client are async and return a CompletionStage):

DeviceClient client;

DeviceInfoMgr deviceInfoMgr;

public CompletionStage<Void> registerDevice(String name) {

    return checkIfNameTaken(name)
        .thenCompose( (unused) -> client.createDevice())
        .thenCompose(deviceResponse -> {
            Device device = deviceResponse.getBody();
            device.setName(name);
            return client.updateDevice(device);
        }).thenApply(unused -> {
            deviceInfoMgr.set(name);
            return (Void)null;
        });
}

private CompletionStage<Void> checkIfNameTaken(String name) {

    return client.getAllDevices()
        .thenCompose(devices -> {

            for(Device dev : devices) {
                if(dev.getName() == name) {
                    //I use a helper for this
                    CompletableFuture<Void> err = new CompletableFuture<>();
                    err.completeExceptionally(new DeviceNameTakenException());
                    return err;
                }
            }
            return CompletableFuture.completedFuture((Void)null);
        });
}

您会看到它具有与以前相同的方法,并且这些方法做他们以前做过的事情,并且以相同的操作顺序来做……但是现在他们返回一个CompletionStage,表明它们可能异步运行,结果可能取决于当这些方法返回时未完成的事情

You see that it has the same methods that it had before, and those methods do the same thing they did before, and they do it with the same sequence of operations... but now they return a CompletionStage, indicating that they may run asynchronously and the results may depend on things that aren't done when those methods return.

这篇关于异步http请求的解耦设计的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆