【发布时间】:2015-05-12 14:40:59
【问题描述】:
我开始更多地接受响应式编程,并尝试将其应用于我的典型业务问题。我经常设计的一种模式是数据库驱动的类。我有一些已定义的单元类,例如ActionProfile,其实例由ActionProfileManager 管理,它从数据库表中创建实例并将它们存储在Map<Integer,ActionProfile> 中,其中Integer 是actionProfileId 键。 ActionProfileManager 可能会定期清除并重新导入数据,并通知所有依赖项从其映射中重新拉取。
public final class ActionProfileManager {
private volatile ImmutableMap<Integer,ActionProfile> actionProfiles;
private ActionProfileManager() {
this.actionProfiles = importFromDb();
}
public void refresh() {
this.actionProfiles = importFromDb();
notifyEventBus();
}
//called by clients on their construction or when notifyEventBus is called
public ActionProfile forKey(int actionProfileId) {
return actionProfiles.get(actionProfiles);
}
private ImmutableMap<Integer,ActionProfile> importFromDb() {
return ImmutableMap.of(); //import data here
}
private void notifyEventBus() {
//notify event through EventBus here
}
}
但是,如果我想让它更具反应性,那么创建地图会破坏 monad。我可以做的一种方法是让Map 本身成为一个 Observable,并返回一个为客户端查找特定密钥的 monad。然而,中间命令式操作可能并不理想,特别是如果我开始使用rxjava-jdbc 时。但是在密集的情况下,hashmap 可能有助于显着提高查找性能。
public final class ActionProfileManager {
private final BehaviorSubject<ImmutableMap<Integer,ActionProfile>> actionProfiles;
private ActionProfileManager() {
this.actionProfiles = BehaviorSubject.create(importFromDb());
}
public void refresh() {
actionProfiles.onNext(importFromDb());
}
public Observable<ActionProfile> forKey(int actionProfileId) {
return actionProfiles.map(m -> m.get(actionProfileId));
}
private ImmutableMap<Integer,ActionProfile> importFromDb() {
return ImmutableMap.of(); //import data here
}
}
因此,对我来说最被动的方法似乎只是在每次刷新时通过 Observable<ActionProfile> 推送数据库中的所有内容,并过滤客户端的最后一个匹配 ID。
public final class ActionProfileManager {
private final ReplaySubject<ActionProfile> actionProfiles;
private ActionProfileManager() {
this.actionProfiles = ReplaySubject.create();
importFromDb();
}
public void refresh() {
importFromDb();
}
public Observable<ActionProfile> forKey(int actionProfileId) {
return actionProfiles.filter(m -> m.getActionProfileID() == actionProfileId).last();
}
private void importFromDb() {
// call onNext() on actionProfiles and pass each new ActionProfile coming from database
}
}
这是最佳方法吗?导致内存泄漏而不被 GC 处理的旧数据呢?维护地图并使其可观察是否更实用?
上述数据驱动类的最佳响应式方法是什么?或者有没有更好的方法我还没有发现?
【问题讨论】:
-
IMO 您可能要考虑为此使用
Redis数据库 - IMO 您可以同时改进您的mapping(使用其键值条目)和您的 observable(因为 Redis 实现了 JMS) -
一直在做一些其他的研究,也许我不应该使用主题,而是我自己的
Observableimplementations github.com/ReactiveX/RxJava/issues/1794 -
您当前方法的目标是为任何请求数据的消费者提供缓存吗?调用刷新的触发器是什么?
-
触发器可能会从 UI 事件中触发,很可能来自 JavaFX 控件。我还可以定期创建一个计时器来刷新业务参数并重建地图。我确实想要某种类型的缓存(我认为),因为新订阅者可以随时在 UI 环境中锁定。但我也不希望保留陈旧的数据。
-
我最终避免使用
Subject,而是选择使用Obersvable.defer()和/或Observable.cache()。我发现Subject的无限热特性在用于支持复杂的 UI 触发流程时会很麻烦,而且我总是不得不调用take(1)以使其对于该流程实例来说是冷的和有限的。
标签: java monads reactive-programming rx-java