2009-07-29 121 views
9

我正在设计一个简单的聊天应用程序(仅供参考)。我一直在想这个聊天应用程序的简单设计。给你概述..这里是规则:适用于简单聊天应用程序的设计模式

  1. 匿名用户输入聊天只是一个绰号。 (用户ID)大概由系统在后台分配。
  2. 他们可以加入(订阅)聊天对话。他会看到来自其他用户的聊天文本出现在指定区域。
  3. 他们可以回复特定的对话,其他人都可以看到该对话。

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

现在这里是我设计它的方式。 (我编码在java中。在真正重要的情况下)

  1. 用户对象 - 两个属性ID和昵称
  2. 消息对象 - 一个简单的信息接口和实现(现在)作为SimpleMessage中,有字符串作为包含消息的属性。
  3. 聊天窗口对象 - 用户和消息的基本组成。因为它有一个用户对象和消息列表。
  4. 聊天会话 - 再次组成。基本上它会有一个聊天窗口列表。每个聊天窗口注册到聊天会话。聊天会话负责在出现新消息时通知所有聊天窗口。 (Observer模式的人?)

好了..所以现在我已经实现观察者模式通过使ChatWindow实施“ChatListener”拍打它有方法被称为“通知(消息)”。所以ChatSession通知每个已注册的ChatWindow。

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

  1. 这种设计是否有意义?如果你认为这是一个CRAP,并给我一个更好的方法;你一定会从我这里得到一个很大的谢意。除了观察者模式之外,所有模式都可以在这里用来简化它或者使其更好。此外,这个设计的任何弱点,如果它是适当的,但可以改善。

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

    无论如何...请让我知道您的意见。也请rem。工作应用程序不是我的意图,我正在寻找一个良好的讨论,好的设计模式的做法和用法。

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

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

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

回答

4

只看User对象,为什么相等取决于ID 昵称?这对我来说似乎有点不直观。我期望如果你有一个id,那么这就是对象的标识,因此你在平等条件下使用什么。

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

还请注意,由于您重写equals(),您还应该override hashCode()。现在,如果hashCode()和equals()依赖于不可变字段(例如id),那么hashCode()的结果将不会改变,并且如果将用户放置在哈希集合中(例如HashMap)那么你以后就不会失去它了(这很混乱)!(),我会保护构造函数和setter对空的昵称(使它们抛出IllegalArgumentExceptions),然后像equals()这样的代码不必担心空昵称(除非'null'具有昵称)。我会为id做同样的事情,因为你将它作为Long(对象)。但这不可能是一个原始的长期?

+0

非常感谢您的宝贵意见。这正是我正在寻找的东西。我会马上接受你的答案,但我会等一会儿;以防人们想出更多答案。 :) – Priyank 2009-07-29 10:53:56

6

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

的几个显著的设计问题,我确实看到有:

  1. 消息接口没有链接回邮件的发送者 - 大多数的聊天记录显示谁说什么,这将是困难的无消息中的用户字段。
  2. 消息接口没有时间属性。这将使清除旧邮件更加困难。
+0

是的..我同意这两点..然而..如果你看看它,目前的消息甚至可以告诉哪个用户发送它,没有时间戳。正计划用一个更全面的impl类为Message接口实现一个impl。这可能会附加时间戳和发件人。 至于坚持这个信息,是的,但我并没有实现这个部分或用户界面,因为我真的没有试图开发应用程序,而只是为了获得现在的设计,对于基本的东东。更多的是设计模式的学习。 这就是说,评论非常感谢。谢谢。 – Priyank 2009-07-29 04:29:04

2

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

看看这个简单的实现,这将足以为您的玩具项目 - eventbus(不再可用)。或者,您可以使用完全成熟的JMS实现,如ActiveMQ

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