オブザーバー パターン スタイルのソリューションを使用して、さまざまな種類のメッセージを送信するためのクリーンなソリューションの設計に問題があります。
TCP ソケットを介して (変更できない) サーバーに接続しているクライアント アプリケーションがあります。メッセージのタイプを定義する「msg」パラメーターを常に含むjsonエンコードされたメッセージを送受信できます。また、複数のクライアントに送信され、自分のクライアントから要求されていないメッセージを受信できることにも注意してください (たとえば、誰かがチャット メッセージを送信した場合)。
例: 接続時に受信{"msg":"ServerInfo","version":"1.0a"}
{"msg":"Ping"}
で返信を送信する{"msg":"Ping","time":1381358623}
{"msg":"Chat", "from":"Person", "text":"Hello everyone"}
いつでも受け取れました
一部のメッセージはより複雑で、ネストされたオブジェクトを持つことができます。たとえば、
{
"msg":"SampleData",
"people":[{
"name":"Joe"
"age":25
},{
"name":"Bob",
"age":30
}]
}
メッセージには数十の異なる種類があり、すべてさまざまな量と種類のフィールドがあります。
私は現在、ソケットをリッスンし、Gson を使用してすべてのメッセージを "msg" パラメータのみを持つ "BasicMessage" クラスに解析するクラスを持っています。すべてのメッセージ タイプ文字列をそれぞれのクラスにマッピングする Map があります。「msg」パラメーターを取得したら、Gson を使用して逆シリアル化する必要があるクラスを検索し、そうすることができます。これで正しいクラスのインスタンスができましたが、ここから設計が崩壊し始めます。
他のさまざまなクラスに、数種類のメッセージのみをサブスクライブできる機能を持たせたいと考えています。問題は、多くの instanceof を必要とするか、すべてのクライアントですべてを再解析することなく、これを行う方法を見つけることができないように見えることです。
私の最初の考えは、次のようにパラメーター化されたインターフェースを使用することでした。
public interface MessageListener<T> {
public void onReceivedMessage(T message);
}
次に、メッセージを逆シリアル化するクラスで、List<MessageListener<Message>>
Message が継承された他のすべての Message の抽象クラスである場所がありました。MessageListener<SpecificMessage>
次に、継承元ではない型消去の問題に遭遇したMessageListener<Message>
ため、クライアントを 1 つの単純なリストに追加する方法がありませんでした。メッセージの種類ごとにリストを作成する必要があるように思えましたが、これも理想的ではありません。この設計のもう 1 つの問題は、別のクラスでパラメーター化したとしても、同じインターフェイスを 2 回実装することはできないため、複数のメッセージ リスナーが必要なクラスのさまざまなメッセージ リスナーに対してのみ匿名の内部クラスを使用するように制限されることです。 .
この状況で使用できるより良いパターンはありますか? これを「きちんと」機能させるには、リフレクションを使用する必要があるように感じます。理想的には、別のメッセージ タイプを追加する場合は、デシリアライズするクラスを追加するだけで済み、メッセージ文字列からそのクラスへのマッピングが必要になるだけで、そのタイプのメッセージのリスナーを追加できるようになります。別のクラス。
前もって感謝します!