当前位置: 首页 > 知识库问答 >
问题:

多个物体在反应器中流动的有效/正确方法是什么

司空通
2023-03-14

我是一个新的反应编程和我的手,我试图建立一个接近真实的例子。

当你看到反应堆教程时,他们会给你很简单的例子,比如。

return userRepository.findById(1);

或者像处理通量,打破“布朗小狐狸”字符串和查找唯一的字母等,但大多数这些教程坚持单一对象,不幸的是,我找不到任何指导线或教程显示一个并排的例子,以输入相同的代码,首先在命令式,然后在反应,这就是为什么我看到许多新手在反应编程面临很多学习问题。

但我的观点是,在实际应用程序中,我们处理多个对象,如下我在Reactor中编写的示例代码所示。抱歉,我还在学习错误的代码。

public Mono<ServerResponse> response(ServerRequest serverRequest) {

        return
                Mono.just(new UserRequest())
                        .map(userRequest -> {
                            Optional<String> name = serverRequest.queryParam("name");
                            if (name.isPresent() && !name.get().isEmpty()) {
                                userRequest.setName(name.get());
                                return userRequest;
                            }
                            throw new RuntimeException("Invalid name");
                        })
                        .map(userRequest -> {
                            Optional<String> email = serverRequest.queryParam("email");
                            if (email.isPresent() && !email.get().isEmpty()) {
                                userRequest.setEmail(email.get());
                                return userRequest;
                            }
                            throw new RuntimeException("Invalid email");
                        })
                        .map(userRequest -> {
                            userRequest.setUuid(UUID.randomUUID().toString());
                            return userRequest;
                        })
                        .flatMap(userRequest ->
                                userRepository
                                        .findByEmail(userRequest.getEmail())
                                        .switchIfEmpty(Mono.error(new RuntimeException("User not found")))
                                        .map(user -> Tuples.of(userRequest, user))
                        )
                        .map(tuple -> {
                            String cookiePrefix = tuple.getT2().getCode() + tuple.getT1().getUuid();
                            return Tuples.of(tuple.getT1(), tuple.getT2(), cookiePrefix);
                        })
                        //Some more chaining here.
                        .flatMap(tuple ->
                                ServerResponse
                                        .ok()
                                        .cookie(ResponseCookie.from(tuple.getT3(), tuple.getT2().getRating()).build())
                                        .bodyValue("Welcome")
                        );

    }

首先考虑上面的代码,我从UserRequest对象开始将querystring映射到该对象中。然后我需要一些数据从数据库等反应链接继续更多的工作做。现在考虑一下

  • 来自第一个链接方法的UserRequest对象和
  • 从db获取的用户文档,然后进行更多的操作,但在链接结束时,我需要这两个对象来处理最终的响应。我在google上找到的唯一实现方法就是元组。但之后的代码看起来更脏了,因为我必须在每个下一个操作符中执行
tuple.getT()
tuple.getT2()

所以最后我想问的是,正确的方式还是我在这里错过了什么。因为我在反应中学到了一件事,数据没有更多的流动,只是在逻辑中间的命令式中,我们得到了哦,我需要另一个变量/对象,所以我在上面定义它并使用它,但在反应中,在第5个或第6个运算符之后,当开发人员意识到哦,我也需要那个对象,在这里,我在第2个运算符中创建的,然后我必须回去,在链接中传递它,得到我的第5个或第6个运算符,这是一个正确的方法。

共有1个答案

楚俊逸
2023-03-14

通常有两种策略可以用来避免“元组地狱”,有时是孤立的,有时是一前一后的:

  • 使用您自己的“自定义”元组类,它更能描述类型(我几乎总是建议在生产代码中使用这种方法,而不是使用内置的元组类);
  • 串联一些map()/flatmap()调用,以便不需要声明元组。

此外,这里还有更多的规则需要记住,这些规则可以帮助解决问题:

    null

如果我们将上面的示例付诸实践,我们可以使用@WITH样式而不是setters将前三个map调用转移到一个“填充”用户对象的方法中(不过如果您真的需要,可以在这里使用setters):

private UserRequest populateUser(UserRequest userRequest, ServerRequest serverRequest) {
    return userRequest
            .withName(serverRequest.queryParam("name")
                    .filter(s -> !s.isEmpty())
                    .orElseThrow(() -> new RuntimeException("Invalid name")))
            .withEmail(serverRequest.queryParam("email")
                    .filter(s -> !s.isEmpty())
                    .orElseThrow(() -> new RuntimeException("Invalid email")))
            .withUuid(UUID.randomUUID().toString());
}

我们还可以将链中从数据库中查找用户的部分转移出去。这部分可能需要某种形式的新类型,但不是元组,而是创建一个单独的类--我们称之为VerifiedUser-它将使用UserRequestUser对象。然后,该类型还可以负责生成响应cookie对象,并通过一个简单的getter提供它。(我将编写verifieduser任务作为作者的练习--这应该非常简单。)

然后我们就会有一个这样的方法:

private Mono<VerifiedUser> lookupUser(UserRequest userRequest) {
    return userRepository
            .findByEmail(userRequest.getEmail())
            .map(user -> new VerifiedUser(userRequest, user)) //VerifiedUser can contain the logic to produce the ResponseCookie
            .switchIfEmpty(Mono.error(new RuntimeException("User not found")));
}

所以现在我们有两个单独的小方法,它们各自承担一个单一的责任。我们还有另一个简单的类型verifieduser,它是一个命名容器类型,比元组更具描述性和实用性。此类型还为我们提供了一个cookie值。

这一过程意味着我们的主要反应链现在可以变得非常简单:

return Mono.just(new UserRequest())
        .map(userRequest -> populateUser(userRequest, serverRequest))
        .flatMap(this::lookupUser)
        .flatMap(verifiedUser ->
                ServerResponse.ok()
                        .cookie(verifiedUser.getCookie())
                        .bodyValue("Welcome")
        );

(顺便说一句,您当然是正确的,在撰写本文的时候,有很多琐碎的教程,但很少有“深入”或“真实世界”的材料。对于相当新的框架来说,这通常是一种情况,但这肯定会使它们很难掌握,并导致大量不可维护的代码出现在野外!)

 类似资料:
  • 我试图在UI测试中使用页面对象模式。许多示例假设在类字段中按(定位器)保存。其他人建议保存WebElement(或SelenideElement,如果您使用的是Selenide)。虽然这两种方法都适用于硬编码定位器,但我不知道如何将其用于路径包含变量的定位器。 例如,如何在类字段中保存此定位器?

  • 问题内容: 我正在与我的CompSci教授交谈,他建议将所有String 方法编写为: 而不是: 这两行都可以编译,但是我想知道第一种方法的好处是什么?我一直都是后一种方式。错了吗 什么是普通/常规? 问题答案: 第一种方法确保执行比较时不会收到 NullPointerException 。当您尝试在不存在的对象上调用方法时,抛出(发生)此异常。 以下是一些相关的切线:仔细阅读风险自负 不过要注意

  • 我是反应编程的新手,我想出的唯一解决方案是+,比如 这是最好的解决方案,还是这个问题有更好的范式?

  • 我刚刚遇到了一个奇怪的问题,这是我第一次在服务器上部署spring boot应用程序 像往常一样,我使用java命令java-jar myApp运行应用程序。罐子 过了一会儿,我看到应用程序停止了,没有留下任何错误消息。 所以我不知道问题出在哪里, 可能的原因是java内存不够,所以我将其增加到7GB,因为它有套接字 但问题依然存在 请注意,我没有docker,服务器是Amazon light s

  • 问题内容: 在Python中,我想在代码中编写多行字典。有几种方法可以格式化它。我想到的是一些: mydict = { “key1”: 1, “key2”: 2, “key3”: 3, } mydict = { “key1”: 1, “key2”: 2, “key3”: 3, } mydict = { “key1”: 1, “key2”: 2, “key3”: 3, } 我知道以上任何一种在语法上

  • 问题内容: 有一种获取layoutInflater的方法: 另一种方法是: 第三个(当我参加活动时)是: 那么它们之间有什么区别? 请注意,当我将第三个充气机发送到适配器时,我的应用程序正常工作。但是,当我发送上下文并通过第二种方式创建充气机时,却没有! 问题答案: 它们之间没有太大区别。 正如文档所说,公共抽象对象getSystemService(字符串名称) LayoutInflater,用于