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

时间:2009-07-29 04:16:25

标签: java design-patterns

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

  1. 匿名用户只需输入昵称即可进入聊天。 (用户ID)可能是由系统在后台分配的。
  2. 他们可以加入(订阅)聊天对话。他会看到其他用户的聊天文本出现在指定区域。
  3. 他们可以回复特定的对话,其他人都应该看到。
  4. 这就是它! (见我告诉过你这是一个简单的聊天应用程序)。所以,我的意图并不是真正的应用;但其中使用的设计模式和对象。

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

    1. 用户对象 - 两个属性id和昵称
    2. 消息对象 - 一个简单的Message接口和实现(现在)作为SimpleMessage,其中String作为包含消息的属性。
    3. 聊天窗口对象 - 基本上是用户和消息的组合。因为它有一个用户对象和消息列表。
    4. 聊天会话 - 再次构成。基本上它会有一个Chat Windows列表。每个聊天窗口都注册到聊天会话。聊天会话负责在出现新消息时通知所有聊天窗口。 (观察者模式是谁?)
    5. 好吧..所以现在我已经通过使ChatWindow实现“ChatListener”模式实现了观察者模式,该模式具有称为“notify(Message)”的方法。所以ChatSession会通知每个注册的ChatWindow。

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

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

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

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

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

        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);
                    }
                }
            }
        }
        

        感谢所有捐助者提前。 干杯

3 个答案:

答案 0 :(得分:6)

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

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

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

答案 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个会话都在后台完成。