我变得绝望,我基于客户端-服务器原理开发了一个简单的Java多用户聊天程序。我已经编写了一个基本的多线程服务器应用程序,并且运行良好。我的问题是基于Swing GUI工具包的客户端。具有运行时循环的基本UI,用于在后台接收消息。我的问题是我想将套接字逻辑与UI分开,这意味着在最好的情况下,我有两个不同的类,一个用于套接字运行时循环,另一个用于管理UI。由于该问题,运行时循环必须将消息通知/添加到UI,所以它们彼此依赖。
MessengerView
是我的主要课程,其中包含swing ui和所有依赖的组件。目前,该类还包含套接字逻辑,但是我想将它们提取到外部类中。ClientRuntime
应该包含套接字逻辑的类... 我的问题是,如何分离它们以及如何连接它们?例如,我尝试通过注册这样的方法来尝试类似摆动的事件:
addListener(MessageArrivedListener listener);
emitMessageArrivedEvent(String message);
问题是,如果事件数量增加,这将非常令人困惑!如前所述,我的第二个选择是将套接字逻辑和ui设计保留在一个类中,但是我认为这是一个坏主意,因为这使得很难为其编写单元测试或发现错误...
在使用C ++的时候,有时会使用朋友类来解决此问题,因为这样可以访问其他类的类成员!但是这种解决方案通常也很混乱,我发现Java没有这样的选择。
那么还有其他方法可以保持swing小部件和套接字逻辑之间的连接,而无需将它们存储在同一类(文件)中吗?
答案 0 :(得分:1)
how could I separate them and how could I connect them?
使用BlockingQueue
连接它们-这是选择连接线程的方式的首选。
ClientRuntime
类必须启动2个线程:一个从阻塞队列中获取请求并将其发送到服务器,第二个不断通过套接字从服务器读取消息并将其发送到UI线程。 UI线程已经为消息输入了阻塞队列:SwingUtilities.invokeLater(Runnable);
对其进行了访问。 ClientRuntime
类不能直接访问UI队列:它从MessengerView
调用一个方法,并将其从套接字接收的内容,二进制数组或json字符串传递给该UI方法,并将其转换为某些{{ 1}}实际上会更新用户界面。
答案 1 :(得分:0)
他们互相依赖
嗯,他们不是真的。 “套接字”层仅关心启动,运行,发布一些消息以及停止。
实际上并不关心/完成所有事情,它只是在被告知时“启动”,处理输入/输出消息,在被要求时发布通知和“停止”。
这基本上是观察者模式,或者,如果您愿意,则是生产者/消费者模式。
因此套接字层需要定义一个愿意使用的行为或契约的“协议”。该合同的一部分将是“如何”通过观察者或通过阻止/只读队列生成有关新消息的通知的方法,这由您决定。
对于UI来说,它稍微复杂一点,因为Swing是单线程的,因此您不应长时间运行或阻塞操作来阻塞UI。在这里类似SwingWorker
的地方会派上用场。
它基本上充当UI和套接字层提供的用于接收消息的机制之间的代理。消息从套接字层进入SwingWorker
,SwingWorker
然后publish
将消息发送到UI的事件线程,然后可以安全地更新到UI
也许以Concurrency in Swing和Worker Threads and SwingWorker开头
我的问题是,如何分离它们以及如何连接它们?例如,我尝试通过注册这样的方法来尝试类似摆动的事件: 问题是,如果事件数量增加,将非常令人困惑!
我不这样认为(恕我直言)。您想要做的是专注于事件的“类”。例如,从上面的内容中,您有“生命周期”事件和“消息”事件。我首先将它们分为两个单独的界面,因为对“消息”事件感兴趣的人可能对“生命周期”事件不那么感兴趣,这样您就可以划分观察者。
您想要尝试的重要概念是正确使用`接口来定义“合同”,这成为实现的“公开”视图,允许您根据自己的想法设计用于不同目的的不同实现变化和成长。这样可以使代码解耦,并允许您更改一部分而不会对API的其他部分产生不利影响