2009-07-29 410 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個會話在後臺完成。