HashMap 与响应式编程

HashMaps vs Reactive Programming

我开始更多地接受响应式编程,并尝试将其应用到我的典型业务问题中。我经常设计的一种模式是数据库驱动的 classes。我有一些已定义的单元 class,例如 ActionProfile,其实例由 ActionProfileManager 管理,它从数据库 table 中创建实例并将它们存储在 Map<Integer,ActionProfile> 中其中 IntegeractionProfileId 键。 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'(例如监听鼠标移动事件)。