场景

我将尽可能简洁。基本上参考此classdiag,我有一个外观管理一个列表SocketManager (管理一个Socket连接)。每个 SocketManager 使用唯一的SocketUserId登录到远程服务器。此外,每个 SocketManager 将接受来自客户端的消息,这些消息发往特定的收件人列表。为了便于讨论,请将这些收件人视为由名称标识的远程数据桶。

客户将发送如下数据:

SocketFacade facade = ...;

byte[] data = ...

facade.sendData( receipient, data );

当SocketFacade启动时,它将查询一个mysql表,该表返回SocketUserId和Receipients之间的1-m关系。我将使用MultiValuedMap表示这种1-m关系。然后,将通过遍历地图来启动多个 SocketManager
(1) Map< SocketUserId, List<Receipient> >

例如假设我们有2个 SocketManager ,分别带有SocketUserIds“alice”和“tom”
            +----SocketManager1 ( "alice" ) for Receipients { "B", "C" }
            |
 SocketFacade
            |
            +----SocketManager2 ( "tom" ) for Receipients { "A", "D" }

问题

关于如何实现sendData方法,我处于困境。基本上,我需要一种从收件人(例如“B”)映射到其负责的 SocketManager (例如SocketManager1)的方法。

假设我这样做
(2) Map< SocketUserId, SocketManager >
(3) Map< Receipient, SocketUserId >
  • 我需要(2)中的值的软件引用吗?
  • 我应该只从收件人映射到 SocketManager 吗?
  • SocketFacade 还支持将使(1)表示的关系发生变异的方法。如果我写入数据库,则(1),(2)和(3)中的内存中数据结构将需要同步更改。 SocketFacade 也必须是线程安全的。最初的想法是拥有某种发布订阅系统,通过该系统,对数据库的添加/删除将导致更改通过回调传播。
    interface Callback
    {
        void receipientAdded( Receipient r );
        void receipientDeleted( Receipient r );
    }
    
  • 最佳答案

    在每个SocketManager中保留对Receipient的引用。这样,您可以避免映射(它需要更多的RAM,速度较慢,并且不添加任何值)。

    SocketManager中,保留Receipient的列表。添加和删​​除Receipient时,更新指向SocketManager的指针。

    SocketFacade中,您需要一个映射,该映射接受SocketUserId并返回SocketManager。该地图是通过查询地图中的ID来填充的。所有经理都存在后,将收件人添加到每个中。这需要两个SQL查询。

    使用任何ORM工具都很容易映射。

    10-06 09:01