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
对象。而且我无法访问 person
和 addressLink
,我在构建 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))
)
)
您还可以使用一些技术来使用容器 类,例如元组或对,以将您需要的所有参数传递到链中,但我认为通常不值得付出努力。
这是以下 类 结构:
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
对象。而且我无法访问 person
和 addressLink
,我在构建 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))
)
)
您还可以使用一些技术来使用容器 类,例如元组或对,以将您需要的所有参数传递到链中,但我认为通常不值得付出努力。