HashMaps与反应式编程

时间:2015-05-12 14:40:59

标签: java monads reactive-programming rx-java

我开始更多地接受反应式编程,并且我正在尝试将其应用于我的典型业务问题。我经常设计的一种模式是数据库驱动的类。我有一些已定义的单元类,如ActionProfile,其实例由ActionProfileManager管理,它从数据库表创建实例,并将它们存储在Map<Integer,ActionProfile>中,其中IntegeractionProfileId密钥。 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。但是,在密集的情况下,散列图可能有助于查找性能。

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会怎么样?维护地图并使其可观察是否更实际?

数据驱动类上面最优化的被动方法是什么?或者有没有更好的方法我没有发现?

1 个答案:

答案 0 :(得分:3)

如果您不关心早期的价值观,使用BehaviorSubject是正确的做法。

请注意,大多数帖子令人沮丧的主题都是在Rx.NET的早期编写的,并且大部分被引用并且没有多少考虑。我将此归因于这样的作者可能并不真正了解主题是如何工作或遇到某些问题而只是声明他们不应该被使用。

我认为主题是一种很好的方式来组织事件(通常来自单个线程)你控制的事件,或者你是事件的来源,事件调度在某种程度上是全球性的[&#39; (比如听老鼠移动事件)。