2008-08-31 57 views
2

我有暴露異步遠程接口的最佳方式的一個問題。暴露遠程接口或對象模型

的條件如下:

  • 的協議是異步
  • 第三方可以在任何時間修改數據
  • 命令往返可以顯著
  • 該模型應該很好地適用於UI相互作用
  • 該協議支持對某些對象的查詢,並因此必須與模型

作爲提高我的技能缺乏在這方面的手段(和溫習一下在一般的Java),我已經開始project創建一個基於Eclipse的前端爲xmms2(如下所述)。

所以,問題是;我應該如何將遠程接口公開爲一個整潔的數據模型(在這種情況下,跟蹤管理和事件處理)?

我從圖案擅用他人名義或具體的例子和補丁:)


通用討論我在這裏的主要目的是瞭解這個類的一般問題,歡迎任何東西。如果我的項目可以從中獲益,那麼很好,但我會嚴格地提出一些建議來開始討論。

我已經實現了一個協議抽象,我稱之爲'client'(出於傳統原因),它允許我使用方法調用來訪問大多數暴露的特性,即使它很不完美,我也很滿意。

由XMMS2守護程序提供的功能是一樣的東西軌道檢索,元數據檢索和操縱,改變播放狀態,負載的播放列表等等,等等。

我在更新到XMMS2的最新的穩定版本的中間,我想我也可以解決一些我目前的實施明顯的弱點。

我的計劃是建立在協議接口的上方,一個允許與守護更自然的交互更好的抽象。目前的'model'實現很難使用,坦率地說相當醜陋(更不用說UI代碼真的很恐怖了)。

今天我有Tracks接口,我可以用它來獲取基於其ID Track類的實例。搜索是通過Collections接口(不幸的命名空間衝突)來實現的,我想這個接口我寧願移動到Tracks。

任何數據都可以由第三方在任何時間進行修改,這應該被適當地反映在模型中,改變的通知分佈式

連接時,通過返回的對象分層結構,看起來像這些接口被暴露此:

  • 連接
    • 播放getPlayback()
      • 播放,暫停,跳步,當前曲目等
      • 揭露回放狀態改變
    • 曲目getTracks()
      • 軌道getTrack(ID)等
      • 揭露跟蹤更新
    • 收藏夾getCollection()
      • 加載和操作播放列表或指定集合
      • 查詢媒體庫
      • 揭露收集更新

回答

2

對於異步位,我會建議檢查爲java.util.concurrent,尤其是Future<T>接口。未來的接口用於表示尚未準備好的對象,但正在單獨的線程中創建。你說對象可以在任何時候被第三方修改,但是我仍然建議你在這裏使用不可變的返回對象,而是有一個單獨的線程/事件日誌,你可以訂閱它以在對象到期時注意到。我很少使用UI進行編程,但我相信使用Futures進行異步調用會讓您擁有響應式GUI,而不是等待服務器回覆的GUI。

對於我建議使用方法鏈來構建查詢對象的查詢,並且方法鏈接返回的每個對象應該是Iterable。類似於Djangos模型。假設你有QuerySet其實施Iterable<Song>。然後您可以撥打allSongs(),這將返回迭代所有歌曲的結果。或者allSongs().artist("Beatles"),你可以在所有Betles歌曲中迭代。甚至allSongs().artist("Beatles").years(1965,1967)等。

希望這有助於作爲一個起點。

0

@Staale:非常感謝!

使用未來進行異步操作很有趣。唯一的缺點是它不提供回調。但後來,我嘗試了這種方法,並看看我的地方:)

我目前正在解決一個類似的問題,使用工作線程和阻塞隊列調度傳入的命令答覆,但該方法不翻譯得非常好。

遠程對象可以修改,但由於我使用線程,我試圖保持對象不可變。我現在的假設是,我會送軌道上的更新通知事件的形式,

somehandlername(int changes, Track old_track, Track new_track) 

或相似的,但後來我可能會結束與同一軌道的幾個版本。

我一定會考慮Djangos方法鏈接。我一直在尋找一些類似的構造,但一直沒能找到一個好的變體。返回可迭代的東西很有趣,但是查詢可能需要一些時間才能完成,而且我不希望在完全構建之前實際執行查詢。

也許類似

Tracks.allSongs().artist("Beatles").years(1965,1967).execute() 

返回一個未來可能的工作...

0

可迭代只有方法迭代得到()或諸如此類。因此,除非實際開始迭代,否則不需要構建任何查詢或執行任何代碼。它確實使你的例子中的執行是多餘的。但是,線程將被鎖定,直到第一個結果可用,所以您可能會考慮使用Executor在單獨的線程中運行查詢的代碼。

0

@Staale

這當然是可能的,但是當你注意,這將使它阻塞(在家裏像由於睡眠盤10秒),這意味着我不能用它來更新UI直。

我可以使用迭代器在單獨的線程中創建結果的副本,然後將其發送到UI,但迭代器本身的解決方案本身相當優雅,但它不會很好地適用。最後,實現IStructuredContentProvider的東西需要返回一個包含所有對象的數組,以便在TableViewer中顯示它,所以如果我可以避免在回調中得到類似的東西... :)

I我會再考慮一下。我可能只是能夠解決一些問題。它的確讓代碼看起來很漂亮。

0

我到目前爲止的結論;

我很在意是否爲Track對象使用getters,或者只是暴露成員,因爲對象是不可變的。

class Track { 
    public final String album; 
    public final String artist; 
    public final String title; 
    public final String genre; 
    public final String comment; 

    public final String cover_id; 

    public final long duration; 
    public final long bitrate; 
    public final long samplerate; 
    public final long id; 
    public final Date date; 

    /* Some more stuff here */ 
} 

如果誰想要知道發生了什麼事情到軌道中,庫將實現這個...

interface TrackUpdateListener { 
    void trackUpdate(Track oldTrack, Track newTrack); 
} 

這是querys是如何構建的。連鎖呼喚你的心中的內容。儘管如此,陪審團依然在get()上。缺少一些細節,比如我應該如何處理通配符和更高級的帶有分離的查詢。我可能只需要一些完成回調功能,可能類似於Asynchronous Completion Token,但我們會看到這一點。也許這會發生在另外一層。

interface TrackQuery extends Iterable<Track> { 
    TrackQuery years(int from, int to); 
    TrackQuery artist(String name); 
    TrackQuery album(String name); 
    TrackQuery id(long id); 
    TrackQuery ids(long id[]); 

    Future<Track[]> get(); 
} 

一些例子:

tracks.allTracks(); 
tracks.allTracks().artist("Front 242").album("Tyranny (For You)"); 

軌道接口是大多隻是的連接,並把各個軌道之間的粘合劑。它將成爲實施或管理元數據緩存的一員(如今,但我想我會在重構期間將其刪除,看看我是否真的需要它)。此外,這提供了medialib軌道更新,因爲通過跟蹤實施它只是太多的工作。

interface Tracks { 
    TrackQuery allTracks(); 

    void addUpdateListener(TrackUpdateListener listener); 
    void removeUpdateListener(TrackUpdateListener listener); 
}