2009-07-29 9 views
9

Sto progettando una semplice applicazione di chat (solo per il calcio di esso). Mi sono chiesto un design semplice per l'applicazione di chat. Per darti una panoramica .. ecco le regole:Modello di design adatto per un'applicazione di chat semplice

  1. L'utente anonimo accede alla chat solo con un nickname. (ID utente) è presumibilmente assegnato dal sistema in background.
  2. Possono partecipare (iscriversi a) una conversazione chat. E vedrà il testo della chat di altri utenti che appaiono nell'area designata.
  3. Possono rispondere a una determinata conversazione e tutti gli altri dovrebbero vederlo.

COSÌ! (Vedi ti ho detto che era una semplice applicazione di chat). Quindi, la mia intenzione non è in realtà l'applicazione; ma il modello di progettazione e gli oggetti utilizzati in esso.

Ora ecco come l'ho progettato. (Sto codifica in java .. in caso che conta davvero)

  1. oggetto utente - Due attributi id e soprannome
  2. Oggetto Messaggio - Un'interfaccia semplice messaggio e l'implementazione (per ora) come SimpleMessage, con un String come attributo per contenere il messaggio.
  3. Oggetto finestra di chat - Fondamentalmente composizione di utente e messaggi. Come ha un oggetto utente e un elenco di messaggi.
  4. Chat sessione - Ancora composizione. Fondamentalmente avrà un elenco di finestre di chat. Ogni finestra di chat si registra in una sessione di chat. La sessione di chat è responsabile di notificare tutte le finestre di chat quando viene visualizzato un nuovo messaggio. (Osservatore modello chiunque?)

Va bene .. così ora ho implementato pattern Observer facendo finestra di chat implementare patter "ChatListener", che ha metodo chiamato "notificare (Messaggio)". Quindi ChatSession notifica ogni ChatWindow registrata.

Ora qui ci sono alcune cose che voglio chiarire/voglio la tua opinione su. 1. Ho bisogno di avere il metodo di de-register anche per tutte le finestre di chat, nel caso in cui una finestra di chat sia chiusa e non voglia ricevere ulteriori notifiche. Ciò significa potenzialmente che dovrei avere un gestore di registrazione centrale "statico" che ha solo un'istanza e quindi qualsiasi finestra di chat dovrebbe essere in grado di annullare la registrazione fornendo un ID di "sessione di chat". Per questo motivo, ogni sessione di chat dovrebbe avere un ID. (Incluso qui). O potrei anche mantenere un'istanza di ChatSession nella finestra di chat, per avere sempre un'istanza pronta. (Odio i singleton perché penso che vadano contro oops). Un altro modo sarebbe quello di non avere il controllo di cancellazione della finestra di chat, con finestra di chat, invece la notifica di chiusura della finestra dovrebbe arrivare direttamente a ChatSession e dovrebbe fare, cosa dovrebbe fare!

  1. Questo progetto ha senso? Se dovessi dire che è un pezzo di CRAP e dammi un approccio ancora migliore; avrai sicuramente un GRANDE GRAZIE da parte mia. Oltre al modello di osservatore, è possibile utilizzare qui tutti i motivi per semplificare o migliorare. Inoltre .. tutti i punti deboli di questo design, se è appropriato ma può essere migliorato.

  2. Anche quando un utente digita un nuovo messaggio nella propria finestra di chat; ha bisogno di essere propagato a tutte le finestre di chat, che è ciò che fa la sessione di chat, ma allo stesso tempo; vuol dire che .. la sessione di chat ha bisogno di ricevere un messaggio con "id della finestra di chat" e un messaggio? E poi lo propaga a tutte le finestre, incluso quello che è il proprietario del messaggio? Qual è un modo migliore per gestire questo.Voglio dire, un modo in cui finestra consente alla sessione di chat di conoscere il messaggio e quindi di chattare su tutte le altre finestre. (Sto pensando che avrà bisogno di un po 'se ... non mi piacciono neanche)

    Comunque ... fammi sapere i tuoi commenti. Inoltre, per favore rem. l'applicazione funzionante non è l'intento, sto cercando una buona discussione, buone pratiche di progettazione e utilizzo.

completo del codice qui sotto, se si dà un alto ... Sentitevi liberi di strappare lo distingue e portare fino questioni relative a quasi tutti i semantica.

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

Grazie a tutti i contributori in anticipo. Cheers

risposta

4

Basta guardare l'oggetto User, perché l'uguaglianza dipende dall'ID e dallo soprannome? Sembra un po 'controintuitivo per me. Mi aspetterei se tu possieda un id, quindi quella è l'identificazione dell'oggetto, e quindi ciò che useresti in una condizione di uguaglianza.

Vedo anche che hai un setter per l'ID utente. Quindi vuoi veramente cambiare l'ID utente? Vedo che è possibile modificare il soprannome, che ha senso. Ma mi aspetto che l'ID rimanga costante.

Nota anche che poiché stai eseguendo l'override di equals(), devi anche override hashCode().

Ora, se hashCode() ed equals() si basano su campi immutabili (ad esempio l'id), i risultati di hashCode() non cambieranno e se si inserisce un utente in una raccolta hash (ad es. HashMap) quindi non lo perderai più tardi (il che è molto confuso)!

Infine (!) Proteggerei il costruttore e i setter contro nickname nulli (farli lanciare IllegalArgumentExceptions) e poi codice come equals() non deve preoccuparsi di un nickname nullo (a meno che 'null' abbia un significato per il soprannome). Farei lo stesso per l'id, dato che hai questo come Long (oggetto). Ma non potrebbe essere un primitivo lungo?

+0

Grazie mille per un prezioso feedback. Questo è quello che stavo cercando esattamente. Avrei accettato la tua risposta come giusta, subito; ma aspetterò solo un po '; nel caso in cui le persone escano con più risposte. :) – Priyank

+0

Va bene. Non mi sono concentrato sullo schema generale come hai chiesto, quindi sospetto che altre risposte siano più appropriate per l''accettazione', ma è utile sapere quanto sopra è utile –

6

Il design di base sembra sano per me. Ovviamente per completare questo, si dovrebbe aggiungere molte più funzionalità. Il design attuale mantiene tutti i messaggi in memoria indefinitamente, ma a un certo punto avrete bisogno del codice per eliminare i vecchi messaggi.

I pochi problemi di progettazione significativi che io vedo sono:

  1. L'interfaccia messaggio non collega indietro il mittente del messaggio - La maggior parte delle chat mostrano chi ha detto cosa, e questo sarà difficile senza un Campo utente nel messaggio.
  2. L'interfaccia del messaggio non ha una proprietà time. Ciò renderà più difficile l'eliminazione dei vecchi messaggi.
+0

Sì .. Sono d'accordo con entrambi i punti .. Comunque .. se lo guardi, attualmente i messaggi possono anche dire quale utente lo ha inviato e nessun timestamp. Stava pianificando di realizzare un impl per l'interfaccia Message con una classe impl più completa. Il che probabilmente aggiungerebbe timestamp e mittente. Per quanto riguarda il persistere del messaggio, sì, quello che mi è venuto in mente, ma non ho implementato quella parte o l'interfaccia utente per quella questione in quanto non sto provando a sviluppare l'applicazione ma solo per ottenere il design giusto per ora, per base cose. Più di un apprendimento di modelli di progettazione. Ciò detto, i commenti sono molto apprezzati. Grazie. – Priyank

2

Suggerirei di esaminare i framework di messaging invece di utilizzare il pattern Observer.

Dai un'occhiata a questa semplice implementazione che sarà sufficiente per il tuo progetto di giocattoli - eventbus (non più disponibile). In alternativa è possibile utilizzare un'implementazione JMS completa come ActiveMQ.

Fondamentalmente consente di definire un bus comune a cui è possibile registrare e annullare la registrazione dei partecipanti, nonché inviare messaggi che tutti i partecipanti vedranno. Il grande vantaggio rispetto al pattern di osservatore è l'accoppiamento molto basso tra i partecipanti - non si registra con ciascun oggetto per ottenere i suoi messaggi - basta registrarsi una volta con il bus. Inoltre, si ottiene un'elaborazione asincrona, diciamo che si hanno 1000 sessioni di chat: se si utilizza observer, significa che per ogni messaggio sarà necessario aggiornare 1000 sessioni. Con il messaggio quadro del messaggio, l'invio è molto veloce e le notifiche su tutte le 1000 sessioni vengono eseguite in background.

Problemi correlati