我正在设计一个简单的聊天应用程序(只是为了它)。我一直想知道这个聊天应用程序的简单设计。为了概述..这里有规则:
这就是它! (见我告诉过你这是一个简单的聊天应用程序)。所以,我的意图并不是真正的应用;但其中使用的设计模式和对象。
现在我就是这样设计的。 (我在java中编码......如果真的很重要)
好吧..所以现在我已经通过使ChatWindow实现“ChatListener”模式实现了观察者模式,该模式具有称为“notify(Message)”的方法。所以ChatSession会通知每个注册的ChatWindow。
现在这里有一些我想澄清/想要你的意见的事情。 1.我还需要为所有聊天窗口取消注册方法,以防聊天窗口关闭并且不想再收到任何通知。这可能意味着,要么我应该有一个“静态”中央注册管理器,它只有一个实例,然后任何聊天窗口应该能够通过提供“聊天会话”ID来取消注册自己。因此,每个聊天会话都应该有一个id。 (包括在内)。或者我也可以在聊天窗口中维护ChatSession的实例,以便始终准备好实例。 (我讨厌单身,因为我觉得他们反对哎呀)。 另一种方法是没有取消注册控制聊天窗口,使用聊天窗口,而窗口关闭的通知应直接进入ChatSession,它应该做什么,应该做什么!
这个设计有意义吗?如果你说这是一个CRAP并给我一个更好的方法;你一定会非常感谢我。除了观察者模式之外,这里可以使用所有模式来简化它或使其更好。此外..这个设计的任何弱点,如果它是合适的但可以改进。
当用户在自己的聊天窗口中输入新消息时;它需要传播到所有聊天窗口,这是聊天会话所做的,但同时;这是否意味着..聊天会话需要获得带有“聊天窗口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<Message> messageList;
private Long id;
public User getUser() {
return user;
}
public List<Message> getMessageList() {
return messageList;
}
public void setUser(User user) {
this.user = user;
}
public void setMessageList(List<Message> messageList) {
this.messageList = messageList;
}
public void addMessageToList(Message newMessage) {
if (this.messageList == null) {
this.messageList = new ArrayList<Message>();
}
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<ChatListener> registeredChatListeners;
public void register(ChatWindow chatWindow) {
if (registeredChatListeners == null)
registeredChatListeners = new ArrayList<ChatListener>();
registeredChatListeners.add(chatWindow);
}
public List<ChatListener> getRegisteredChatListeners() {
return registeredChatListeners;
}
public void setRegisteredChatWindows(
List<ChatListener> 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);
}
}
}
}
感谢所有捐助者提前。 干杯
答案 0 :(得分:6)
基本设计看起来很合理。显然要完成这个,你需要添加更多的功能。当前设计将所有消息无限期地保存在内存中,但在某些时候您将需要用于清除旧消息的代码。
我看到的几个重要的设计问题是:
答案 1 :(得分:5)
只看User
对象,为什么等式依赖于id 和昵称?这对我来说似乎有些直觉。我希望如果你有一个id,那就是对象的标识,以及你在平等条件下使用的内容。
我还看到你有一个用户ID的setter。所以你真的想改变用户名吗?我看到你可以改变昵称,这是有道理的。但我希望id能保持不变。
另请注意,由于您要覆盖equals(),因此您还应该override hashCode()。
现在,如果hashCode()和equals()依赖于不可变字段(例如id),那么hashCode()的结果不会改变,如果你将一个User放在一个哈希集合中(例如HashMap)那么你以后不会失去它(这非常令人困惑)!
最后(!)我会保护构造函数和setter免受空昵称(使它们抛出IllegalArgumentExceptions)然后像equals()这样的代码不必担心空昵称(除非'null'对于昵称)。我会为id做同样的事情,因为你将它作为Long(对象)。但这不是一个原始的长期吗?
答案 2 :(得分:2)
我建议调查消息传递框架而不是使用Observer模式。
看一下这个简单的实现,它对你的玩具项目来说已经足够了 - eventbus(不再可用)。或者,您可以使用ActiveMQ等完整的JMS实现。
基本上,它允许您定义一个公共总线,您可以注册和取消注册参与者,还可以发送所有参与者将看到的消息。与观察者模式相比的最大优势是参与者之间的耦合非常低 - 您没有注册每个对象来获取他的消息 - 您只需在总线上注册一次。此外,您可以获得异步处理 - 假设您有1000个聊天会话 - 如果您使用观察者,则意味着每完成一条消息就需要更新1000个会话。使用消息框架消息发送非常快,并且通知所有1000个会话都在后台完成。