2015-05-12 47 views
4

我開始接受更多的反應式編程,我試圖將它應用於我典型的業務問題。我經常設計的一種模式是數據庫驅動的類。我有一些定義的單元類,如ActionProfile,它們的實例由ActionProfileManager管理,該類創建數據庫表中的實例並將它們存儲在Map<Integer,ActionProfile>中,其中IntegeractionProfileId鍵。 ActionProfileManager可能會定期清除並重新導入數據,並通知所有依賴關係重新從其地圖中拉出。HashMap vs反應式編程

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'd?維護地圖並使其可觀察是否更實用?

以上對數據驅動類最優化的反應方法是什麼?還是有沒有更好的方法,我沒有發現?

+0

IMO你可能會考慮使用'Redis'數據庫 - IMO你可以改進你的'map'ping(使用它的鍵值條目)和你的觀察值(因爲Redis實現JMS) – ControlAltDel

+0

一直在做一些其他的研究,也許我不應該使用主題,而應該使用我自己的'Observable'實現https://github.com/ReactiveX/RxJava/issues/1794 – tmn

+0

您當前的方法的目標是爲請求數據的任何客戶提供緩存?調用刷新的觸發器是什麼? – benjchristensen

回答

3

使用BehaviorSubject是正確的做法,如果你不關心早期值。

注意大多數後抑制主題是在Rx.NET的早期寫的,並且大多被引用一遍又一遍,沒有太多的想法。我將這歸因於這樣的可能性,即這些作者並不真正理解主體如何工作或遇到與他們有關的問題,並且宣稱他們不應該被使用。

我覺得主題是一種很好的方式來組播事件(通常來自單個線程),或者您是事件的來源,事件分派有點「全局」(比如聽老鼠移動事件)。

+0

您對使用hashmaps的原始問題有任何意見嗎?但是,謝謝,這對我的第二個問題很有幫助。 – tmn

+0

我真的不明白這個問題。 – akarnokd

+0

對於原來的問題,我想我會繼續在'BehaviorSubject'內粘貼'Map',並在查找時將'Observable'映射到它。雖然不是純粹的反應,但它似乎是最乾淨的,並且最不容易出現大量數據的性能問題。 – tmn