RxJava:使用反应式方法处理命令式任务

RxJava: process imperative task using reactive approach

这是以下 类 结构:

class SomeEntity {
    private Collection<SomeData> dataCollection;
    private BigDecimal price;
    ...
}

class SomeData {
    private Long personId;
    ...
}

class Person {
    private Collection<AddressLink> addressesLinks; //AddressLink is a representation of the link to the address entity
    ...
} 

我需要为每个地址创建 ShipmentData。它可以使用命令式方法以这种方式实现:

var loadedPersons = entity.getDataCollection().stream()
                .map(SomeData::getPersonId)
                .map(personRepository::loadById)
                .collect(Collectors.toList());

var personToAddressesLinkMap = loadedPersons.stream()
        .collect(Collectors.toMap(key -> key, val -> List.of(val.getAddressesLinks())));

var result = createShipmentData(entity, personToAddressesLinkMap);

ShipmentData 创建方法可能如下所示:

private static List<ShipmentData> createShipmentData(SomeEntity entity, Map<Person, List<Collection<AddressLink>>> personToAddressesLinkMap) {
    List<ShipmentData> result = new ArrayList<>();

    ...

    ShipmentData data = new ShipmentData();
    data.setTargetId(...); // Person.addressLink
    data.setRecepientId(...); // SomeEntity.someData.personId
    data.setPrice(...); // SomeEntity.price
    data.setSourceId(...); //SomeEntity.someData.id
    data.setCreationDate(LocalDateTime.now());

    ...

    return result;
}

但是我 运行 正在执行一个类似的任务,应该使用反应式方法 (RxJava) 来完成。但我不能从反应范式的角度开始思考。这是我拥有的:

Observable.fromIterable(entity.getDataCollection())
    .flatMapSingle(someData -> personRepository.loadById(someData.getPersonId()))
    .flatMapIterable(person -> person.getAddressesLinks())
    .flatMapSingle(addressLink -> addressRepository.findAddressByLink(addressLink))
    .map(address -> createShipmentData(address))
    ...
    
private createShipmentData(Address address) {
    ShipmentData data = new ShipmentData();
    
    data.setTargetId(...); // Person.addressLink
    data.setRecepientId(...); // SomeEntity.someData.personId
    data.setPrice(...); // SomeEntity.price
    data.setSourceId(...); //SomeEntity.someData.id
    data.setCreationDate(LocalDateTime.now());

    return data;
}

这个反应流在访问方面将数据缩小到 Address 对象。而且我无法访问 personaddressLink,我在构建 ShipmentData 期间需要它。

如何使用反应式方法处理此类场景?我正在考虑收集一些外部变量中的所有数据,然后将所有数据传递给 createShipmentData 方法。但对我来说这听起来像是代码的味道。

最简单的方法是使用嵌套来保持对您需要引用的变量的访问。以下链为您提供 Obsevable<ShipmentData>:

Observable.fromIterable(entity.getDataCollection())
    .flatMap(someData -> personRepository.loadById(someData.getPersonId())
        .flatMapObservable(person -> Observable.fromIterable(person.getAddressesLinks())
            .flatMapSingle(addressLink -> addressRepository.findAddressByLink(addressLink))
            .map(address -> createShipmentData(someData, person, address))
        )
    )

添加辅助方法可以清理一些:

private Observable<Address> getAddresses(Person person) {
  return Observable.fromIterable(person.getAddressesLinks())
      .flatMapSingle(addressLink -> addressRepository.findAddressByLink(addressLink));
}

Observable.fromIterable(entity.getDataCollection())
    .flatMap(someData -> personRepository.loadById(someData.getPersonId())
        .flatMapObservable(person -> getAddresses(person)
            .map(address -> createShipmentData(someData, person, address))
        )
    )

您还可以使用一些技术来使用容器 类,例如元组或对,以将您需要的所有参数传递到链中,但我认为通常不值得付出努力。