适用于简单聊天应用程序的设计模式

我正在设计一个简单的聊天应用程序(只是为了它的一脚)。 我一直想知道该聊天应用程序的简单设计。 为了给你概述..这里是规则:

  1. 匿名用户只需输入昵称即可进入聊天。 (用户ID)可能是由系统在后台分配的。
  2. 他们可以加入(订阅)聊天对话。 他会看到其他用户的聊天文本出现在指定区域。
  3. 他们可以回复特定的对话,其他人都应该看到。

而已! (见我告诉过你这是一个简单的聊天应用程序)。 所以,我的意图不是真正的应用程序; 但其中使用的设计模式和对象。

现在我就是这样设计的。 (我在java编码..如果真的很重要)

  1. 用户对象 – 两个属性id和昵称
  2. 消息对象 – 一个简单的Message接口和实现(现在)作为SimpleMessage,其中String作为包含消息的属性。
  3. 聊天窗口对象 – 基本上是用户和消息的组合。 因为它有一个用户对象和消息列表。
  4. 聊天会话 – 再次组成。 基本上它会有一个Chat Windows列表。 每个聊天窗口都注册到聊天会话。 聊天会话负责在出现新消息时通知所有聊天窗口。 (观察者模式有人吗?)

好吧..所以现在我已经通过使ChatWindow实现“ChatListener”模式实现了观察者模式,该模式具有称为“notify(Message)”的方法。 所以ChatSession会通知每个注册的ChatWindow。

现在这里有一些我想澄清/想要你的意见的事情。 1.我还需要为所有聊天窗口取消注册方法,以防聊天窗口关闭并且不想再收到任何通知。 这可能意味着,要么我应该有一个“静态”中央注册管理器,它只有一个实例,然后任何聊天窗口应该能够通过提供“聊天会话”ID来取消注册自己。 因此,每个聊天会话都应该有一个id。 (包括在内)。 或者我也可以在聊天窗口中维护ChatSession的实例,以便始终准备好实例。 (我讨厌单身人士,因为我认为他们反对哎呀)。 另一种方法是没有取消注册控制聊天窗口,使用聊天窗口,而窗口关闭的通知应直接进入ChatSession,它应该做什么,应该做什么!

  1. 这个设计有意义吗? 如果你说这是一个CRAP并给我一个更好的方法; 你一定会非常感谢我。 除了观察者模式之外,这里可以使用所有模式来简化它或使其更好。 此外..这个设计的任何弱点,如果它是合适的,但可以改进。

  2. 此外,当用户在他自己的聊天窗口中键入新消息时; 它需要传播到所有聊天窗口,这是聊天会话所做的,但同时; 这是否意味着..聊天会话需要获得带有“聊天窗口ID”和消息的消息? 然后它将它传播到所有窗口,包括作为消息所有者的窗口? 什么是更好的方法来处理这个问题。 我的意思是,窗口让聊天会话知道消息,然后聊天会话到所有其他窗口。 (我觉得它需要一些,如果……也不喜欢它们)

    无论如何……请告诉我你的意见。 还请你好。 工作申请不是意图,我正在寻找一个很好的讨论,良好的设计模式实践和使用。

下面的完整代码,如果它给你一个高…随意撕开它,并提出几乎任何语义相关的问题。

package com.oo.chat; public class User { private Long userId; private String nickname; public User(Long userId, String nickname) { this.userId = userId; this.nickname = nickname; } public void setUserId(Long userId) { this.userId = userId; } public void setNickname(String nickname) { this.nickname = nickname; } public Long getUserId() { return userId; } public String getNickname() { return nickname; } public boolean equals(Object objectToCompare) { if (!(objectToCompare instanceof User)) { return false; } User incoming = (User) objectToCompare; if (incoming.getNickname() != null && incoming.getUserId() != null) { if (incoming.getNickname().equalsIgnoreCase(this.nickname) && incoming.getUserId().equals(this.userId)) return true; } return false; } } package com.oo.chat; public interface Message { public String getValue(); public void setValue(String value); } package com.oo.chat; public class SimpleMessage implements Message { private String value; public SimpleMessage() { } public SimpleMessage(String value) { this.value = value; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } } package com.oo.chat; public interface ChatListener { public void notify(Message newMessage); } package com.oo.chat; import java.util.ArrayList; import java.util.List; public class ChatWindow implements ChatListener { private User user; private List messageList; private Long id; public User getUser() { return user; } public List getMessageList() { return messageList; } public void setUser(User user) { this.user = user; } public void setMessageList(List messageList) { this.messageList = messageList; } public void addMessageToList(Message newMessage) { if (this.messageList == null) { this.messageList = new ArrayList(); } this.messageList.add(newMessage); } public void notify(Message newMessage) { addMessageToList(newMessage); } public Long getId() { return id; } public void setId(Long id) { this.id = id; } } package com.oo.chat; import java.util.ArrayList; import java.util.List; public class ChatSession { private List registeredChatListeners; public void register(ChatWindow chatWindow) { if (registeredChatListeners == null) registeredChatListeners = new ArrayList(); registeredChatListeners.add(chatWindow); } public List getRegisteredChatListeners() { return registeredChatListeners; } public void setRegisteredChatWindows( List registeredChatListeners) { this.registeredChatListeners = registeredChatListeners; } public void incomingMessage(Long chatListenerId, Message message) { publish(message); } protected void publish(Message messageToPublish) { if (registeredChatListeners != null) { for (ChatListener eachListener : registeredChatListeners) { eachListener.notify(messageToPublish); } } } } 

感谢所有贡献者提前。 干杯

只是看看User对象,为什么等式依赖于id 昵称? 这对我来说似乎有点直观。 我希望你有一个id,那就是对象的标识,以及你在平等条件下使用的东西。

我还看到你有一个用户ID的setter。 所以你真的想改变用户ID吗? 我知道你可以改变昵称,这是有道理的。 但我希望id能保持不变。

另请注意,由于您要覆盖equals(),因此还应覆盖hashCode() 。

现在,如果hashCode()和equals()依赖于不可变字段(例如id),那么hashCode()的结果将不会改变,如果你将一个User放在一个散列集合(例如HashMap)中,那么你就是以后不会失去它(这是非常令人困惑的)!

最后(!)我会保护构造函数和setter免受空昵称(使它们抛出IllegalArgumentExceptions),然后像equals()这样的代码不必担心空昵称(除非’null’对昵称有意义)。 我会对id做同样的事情,因为你将它作为Long(对象)。 但这不可能是一个原始的长期?

基本设计看起来很合理。 显然要完成这个,你需要添加更多的function。 当前设计将所有消息无限期地保存在内存中,但在某些时候,您将需要用于清除旧消息的代码。

我看到的几个重要的设计问题是:

  1. 消息接口不链接消息的发送者 – 大多数聊天显示谁说了什么,如果没有消息中的用户字段,这将很难。
  2. 消息接口没有时间属性。 这将使清除旧邮件变得更加困难。

我建议调查消息传递框架而不是使用Observer模式。

看看这个简单的实现,这对您的玩具项目来说已经足够了 – 事件总线 (不再可用)。 或者,您可以使用像ActiveMQ这样完整的JMS实现。

基本上,它允许您定义一个公共总线,您可以注册和注销参与者,还可以发送所有参与者将看到的消息。 与观察者模式相比的最大优势是参与者之间的耦合非常低 – 您没有注册每个对象来获取他的消息 – 您只需在总线上注册一次。 此外,您可以获得异步处理 – 假设您有1000个聊天会话 – 如果您使用观察者,则意味着每完成一条消息就需要更新1000个会话。 使用消息框架消息发送非常快,并且通知所有1000个会话都在后台完成。