HashMap 与响应式编程
HashMaps vs Reactive Programming
我开始更多地接受响应式编程,并尝试将其应用到我的典型业务问题中。我经常设计的一种模式是数据库驱动的 classes。我有一些已定义的单元 class,例如 ActionProfile
,其实例由 ActionProfileManager
管理,它从数据库 table 中创建实例并将它们存储在 Map<Integer,ActionProfile>
中其中 Integer
是 actionProfileId
键。 ActionProfileManager
会周期性的清空并重新导入数据,并通知所有依赖重新从它的map中拉取。
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,而 return 成为一个为客户端查找特定键的 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 处理的旧数据怎么办?维护地图并使其可观察是否更实用?
以上针对数据驱动 classes 的最佳反应方法是什么?或者有没有更好的方法我还没有发现?
如果您不关心早期的值,那么在这里使用 BehaviorSubject
是正确的做法。
请注意,大多数 post 令人沮丧的主题是在 Rx.NET 的早期写成的,并且大部分被一遍又一遍地引用而没有经过深思熟虑。我将此归因于这样的可能性,即这些作者并不真正了解主题的工作原理或 运行 遇到一些问题而只是宣布不应使用它们。
我认为 Subjects 是一种很好的多播事件(通常来自单个线程)的方式,您可以在其中控制或您是事件的来源,并且事件调度有点 'global'(例如监听鼠标移动事件)。
我开始更多地接受响应式编程,并尝试将其应用到我的典型业务问题中。我经常设计的一种模式是数据库驱动的 classes。我有一些已定义的单元 class,例如 ActionProfile
,其实例由 ActionProfileManager
管理,它从数据库 table 中创建实例并将它们存储在 Map<Integer,ActionProfile>
中其中 Integer
是 actionProfileId
键。 ActionProfileManager
会周期性的清空并重新导入数据,并通知所有依赖重新从它的map中拉取。
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,而 return 成为一个为客户端查找特定键的 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 处理的旧数据怎么办?维护地图并使其可观察是否更实用?
以上针对数据驱动 classes 的最佳反应方法是什么?或者有没有更好的方法我还没有发现?
如果您不关心早期的值,那么在这里使用 BehaviorSubject
是正确的做法。
请注意,大多数 post 令人沮丧的主题是在 Rx.NET 的早期写成的,并且大部分被一遍又一遍地引用而没有经过深思熟虑。我将此归因于这样的可能性,即这些作者并不真正了解主题的工作原理或 运行 遇到一些问题而只是宣布不应使用它们。
我认为 Subjects 是一种很好的多播事件(通常来自单个线程)的方式,您可以在其中控制或您是事件的来源,并且事件调度有点 'global'(例如监听鼠标移动事件)。