我正在尝试通过重构一些当前阻塞代码来学习反应式编程。我多次遇到在Mono
序列中设置一些可变数据对象的状态而不订阅它的问题。在旧代码中,对象字段的值是由一些阻塞服务计算的,我现在也在Mono
中这样做。
到目前为止,我通常(ab)使用持平地图
来获得预期的行为:
java prettyprint-override">initExpensiveObject().flatMap(expObj -> initExpensiveField(expObj).map(expField -> {
expObj.setExpensiveField(expField);
return expObj;
})).subscribe(expObj -> System.out.println("expensiveField: " + expObj.getExpensiveField()));
import reactor.core.publisher.Mono;
public class Main {
/**
* Expensive, lazy object instantiation
*/
public static Mono<ExpensiveObject> initExpensiveObject() {
return Mono.fromCallable(ExpensiveObject::new);
}
/**
* Expensive, async mapping (i.e. database access, network request):
* ExpensiveObject -> int
*/
public static Mono<Integer> initExpensiveField(ExpensiveObject expObj) {
return Mono.just(1);
}
public static class ExpensiveObject {
private int expensiveField = -1;
public int getExpensiveField() {
return expensiveField;
}
public void setExpensiveField(int expensiveField) {
this.expensiveField = expensiveField;
}
}
}
虽然这种< code > flat map -模式有效,但我觉得应该有一种更具反应性的解决方案。考虑到仅在< code>Mono中就有如此多的操作符,为了改变其状态而从一个对象“映射”到同一个对象,直觉上感觉是错误的。然而,“副作用”操作符(< code>doOn*)不允许在没有订阅的情况下轻易转换另一个发布者。
如果我的问题没有微不足道的解决方案,我非常愿意接受设计改进,因为代码的设计仍然是顺序的。
虽然这种平面图模式有效,但我觉得应该有一种更具反应性的解决方案。
这可能不是你想听到的答案,但是反应性的解决方案是完全抛弃可变性。在更复杂的例子中,在反应链中传递可变对象可能会导致意外的副作用,这可能会导致一些很难跟踪的错误。完全重构可变性要容易得多。
如果我的问题没有微不足道的解决方案,我非常愿意进行设计改进
我认为“最少变化”的方法是:
ExpensiveObject
immutable. Remove the setter method, and provide another constructor that takes an explicit value for expensiveField
.withExpensiveField()
(or ofExpensiveField()
, or something else entirely, take your pick!) method on ExpensiveObject
that takes a Mono<Integer>
for expensiveField
and returns a Mono<ExpensiveObject>
.flatMap()
call, and no mutable objects in sight: initExpensiveObject()
.flatMap(expObj -> expObj.withExpensiveField(initExpensiveField(expObj)))
.subscribe(expObj -> System.out.println("expensiveField: " + expObj.getExpensiveField()));
上面的代码有修改:
public class Main {
/**
* Expensive, lazy object instantiation
*/
public static Mono<ExpensiveObject> initExpensiveObject() {
return Mono.fromCallable(ExpensiveObject::new);
}
/**
* Expensive, async mapping (i.e. database access, network request):
* ExpensiveObject -> int
*/
public static Mono<Integer> initExpensiveField(ExpensiveObject expObj) {
return Mono.just(1);
}
public static final class ExpensiveObject {
private final int expensiveField;
public ExpensiveObject() {
expensiveField = -1;
}
private ExpensiveObject(int expensiveField) {
this.expensiveField = expensiveField;
}
public int getExpensiveField() {
return expensiveField;
}
public Mono<ExpensiveObject> withExpensiveField(Mono<Integer> expensiveField) {
return expensiveField.map(ExpensiveObject::new);
}
}
}
您可能希望根据最终设计更改上述内容(例如,
方法在单个字段对象上没有多大意义),但这会跨越主要思想。
我有一张这样的地图<代码>地图 钥匙是数字1,2,3,4。。。学生对象是: 我想做的是把它转换成地图 我可以使用这些代码对地图进行分组,但summingDouble不适用于BigDecimal。此外,我无法将我的studentMap转换为StudentInfo地图:( 我的学生信息对象是:
作为项目Reactor的用户,也想使用Spring集成,我想执行以下操作,这将以这样的方式工作: 一开始,我认为解决方案是执行以下错误代码: 当然,由于问题,它无法工作。我想知道如何一个接一个地执行操作(例如,在CockroachDB写入完成之前不要继续脉冲星写入,如果第一次操作失败,请停止这些消息的流)。 我正在考虑使用Spring集成事务支持,但我担心它在Retor中的使用。 我还看到有一种叫
从静态初始值设定项初始化对象引用 将对它的引用存储到volatile字段或atomicreference 将对它的引用存储到正确构造的对象的最后一个字段 将对它的引用存储到由锁正确保护的字段中。 但是,我对第二个成语感到困惑。因为只能保证引用对另一个线程是可见的,但它没有它所引用的对象构造的同步。那么它如何保证可变对象是正确构造的,构造这个对象的线程是什么,被另一个线程打断了呢?
问题内容: 我如何测试python中两个JSON对象是否相等,而忽略列表的顺序? 例如 … JSON文档a: JSON文档b: 并且应该比较相等,即使列表的顺序不同。 问题答案: 如果你想要两个具有相同元素但顺序不同的对象相等,那么显而易见的事情是比较它们的排序后的副本-例如,以JSON字符串和表示的字典: …但这是行不通的,因为在每种情况下,”errors”顶层dict的项都是具有相同元素的列表
问题内容: 我如何测试python中两个JSON对象是否相等,而忽略列表的顺序? 例如 … JSON文档 a : JSON文档 b : 并且即使列表的顺序不同,也应该比较相等。 问题答案: 如果要使两个具有相同元素但顺序不同的对象相等,那么显而易见的事情是比较它们的排序后的副本-例如,以JSON字符串和表示的字典: …但这是行不通的,因为在每种情况下,顶层dict的项都是具有相同元素的列表,但是顺
及其不安全的发布: 可以抛出AssertionError,我同意。作者写道,这是因为不安全的出版,但另一方面没有答案:什么才是正确的出版方式?它们表示了4个安全发布习惯用语,但我不明白,为什么它们会在上面的情况下起作用: 要安全地发布对象,必须同时使对对象的引用和对象的状态对其他线程可见。通过以下方法可以安全地发布构造正确的对象: null 这里是我的第一个问题,谢谢你的帮助!