2

非同期リモート インターフェイスを公開する最善の方法について質問があります。

条件は次のとおりです。

  • プロトコルは非同期です
  • 第三者はいつでもデータを変更できます
  • コマンドの往復は重要な場合があります
  • モデルは UI インタラクションに適している必要があります
  • プロトコルは特定のオブジェクトに対するクエリをサポートしているため、モデルもサポートする必要があります

この分野で不足しているスキルを改善する手段として (および Java 全般をブラッシュアップする手段として)、xmms2用の Eclipse ベースのフロントエンドを作成するプロジェクトを開始しました(後述)。

それで、問題は次のとおりです。リモート インターフェイスを適切なデータ モデルとして公開するにはどうすればよいですか (この場合は、管理とイベント処理を追跡します)。

一般的な議論からパターン名の削除、具体的な例やパッチまで、何でも歓迎します :)


ここでの私の主な目標は、このクラスの問題全般について学ぶことです。私のプロジェクトがそれから利益を得ることができるなら、それは結構ですが、議論を始めるための何かを持っていることを厳密に提示します.

私は「クライアント」と呼ぶプロトコル抽象化を実装しました(従来の理由から)。これにより、メソッド呼び出しを使用してほとんどの公開された機能にアクセスできますが、それは完全ではありませんが満足しています。

xmms2 デーモンによって提供される機能には、トラックの検索、メタデータの取得と操作、再生状態の変更、プレイリストのロードなどがあります。

私は xmms2 の最新の安定版リリースに更新している最中であり、現在の実装の明らかな弱点のいくつかを修正したほうがよいと考えました。

私の計画は、デーモンとのより自然な相互作用を可能にするプロトコル インターフェイスの上に、より良い抽象化を構築することです。現在の「モデル」の実装は使いにくく、率直に言って非常に醜いです (本当に恐ろしい atm である UI コードは言うまでもありません)。

現在、ID に基づいてTrackクラスのインスタンスを取得するために使用できるTracksインターフェイスがあります。検索はCollectionsインターフェイス (残念ながら名前空間の競合) を介して実行されますが、これはむしろ Tracks に移動したいと思います。

どのデータも第三者によっていつでも変更される可能性があり、これは配布されるモデルと変更通知に適切に反映されるべきです

これらのインターフェイスは、接続時に次のようなオブジェクト階層を返すことによって公開されます。

  • 繋がり
    • プレイバック getPlayback()
      • 再生、一時停止、ジャンプ、現在のトラックなど
      • 再生状態の変更を公開する
    • トラック getTracks()
      • 追跡 getTrack(id) など
      • トラックの更新を公開する
    • コレクション getCollection()
      • プレイリストまたは名前付きコレクションを読み込んで操作する
      • メディア ライブラリのクエリ
      • コレクションの更新を公開する
4

5 に答える 5

2

非同期ビットについてはjava.util.concurrent、特にFuture<T>インターフェイスにチェックインすることをお勧めします。futureインターフェースは、まだ準備ができていないが、別のスレッドで作成されているオブジェクトを表すために使用されます。オブジェクトはサードパーティによっていつでも変更できるとのことですが、ここでは不変のリターンオブジェクトを使用することをお勧めします。代わりに、オブジェクトの有効期限が切れたときに通知を受け取るためにサブスクライブできる別のスレッド/イベントログを用意します。UIを使ったプログラミングはほとんどありませんが、非同期呼び出しにFuturesを使用すると、サーバーの応答を待っていたGUIではなく、応答性の高いGUIを使用できるようになると思います。

クエリの場合、メソッドチェーンを使用してクエリオブジェクトを作成することをお勧めします。メソッドチェーンによって返される各オブジェクトは、である必要がありますIterable。Djangosモデルと同様です。QuerySetを実装しているとしましょうIterable<Song>allSongs()次に、すべての曲を反復処理した結果を返す呼び出しを行うことができます。またはallSongs().artist("Beatles")、そして、あなたはすべてのBetlesの曲を反復することができます。またはallSongs().artist("Beatles").years(1965,1967)など。

これが出発点として役立つことを願っています。

于 2008-08-31T20:52:01.193 に答える
0

@ Staale:たくさんありがとう!

非同期操作にFutureを使用するのは興味深いことです。唯一の欠点は、コールバックが提供されないことです。しかし、もう一度、私はそのアプローチを試し、それが私をどこに導いたかを見てください:)

私は現在、着信コマンド応答をディスパッチするためのワーカースレッドとブロッキングキューを使用して同様の問題を解決していますが、そのアプローチはあまりうまく変換されません。

リモートオブジェクトは変更できますが、私はスレッドを使用しているため、オブジェクトを不変に保つようにしています。私の現在の仮説は、フォームのトラック更新に関する通知イベントを送信するというものです。

somehandlername(int changes, Track old_track, Track new_track)

または同様ですが、同じトラックの複数のバージョンになってしまう可能性があります。

私は間違いなくDjangosメソッドチェーンを調べます。私はいくつかの同様の構成を調べてきましたが、良いバリアントを思い付くことができませんでした。反復可能なものを返すのは興味深いことですが、クエリが完了するまでに時間がかかる可能性があり、完全に構築される前に実際にクエリを実行したくありません。

おそらく次のようなもの

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

未来を返すことはうまくいくかもしれません...

于 2008-08-31T21:23:35.440 に答える
0

Iterable には、メソッド Iterator get() またはそのようなものしかありません。したがって、実際に反復を開始するまで、クエリを作成したり、コードを実行したりする必要はありません。あなたの例の実行は冗長になります。ただし、最初の結果が得られるまでスレッドはロックされるため、Executor を使用して別のスレッドでクエリのコードを実行することを検討してください。

于 2008-08-31T22:13:33.727 に答える
0

@スターレ

確かに可能性はありますが、お気づきのように、それはブロックします (スリープ状態のディスクのために自宅で 10 秒程度)。つまり、UI を直接更新するために使用することはできません。

イテレータを使用して別のスレッドで結果のコピーを作成し、それを UI に送信することもできますが、イテレータ ソリューション自体はかなり洗練されていますが、うまく収まりません。最後に、IStructuredContentProviderを実装するものは、 TableViewerに表示するためにすべてのオブジェクトの配列を返す必要があるため、コールバックからそのようなものを取得することで逃げることができれば... :)

もう少し考えてみます。私は何かを解決することができるかもしれません。コードに見栄えを与えます。

于 2008-08-31T22:57:06.073 に答える
0

これまでの私の結論;

オブジェクトが不変であるため、Track オブジェクトにゲッターを使用するか、単にメンバーを公開するかで悩んでいます。

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);
}

これがクエリの構築方法です。心のコンテンツへのチェーンコール。ただし、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);
}
于 2008-09-01T13:23:18.830 に答える