Diciamo che ho un'applicazione di chat che gestisce stanze, utenti e messaggi. Sto costruendo questo come un'opportunità per praticare alcuni servizi / manager / web separazione e insegnare a me stesso una buona progettazione dell'applicazione.
Con le seguenti classi:
Modello:
public class Room {
private final String id = UUID.randomUUID().toString();
private boolean open = true;
private List<Message> messages = new ArrayList<Message>();
public void addMessage(Message m) {
synchronized(messages) {
messages.add(m);
}
}
public void close() {
this.open = false;
}
public List<Message> getMessages() {
synchronized(messages) {
return new ArrayList<>(messages);
}
}
}
Responsabile:
public interface RoomManager {
public void add(Room r);
public Room get(String id);
}
Servizio:
public class RoomService {
public void postMessage(Message m, Room r) {
if (!r.isOpen()) {
throw new IllegalArgumentException("Room " + r + " is closed");
}
r.addMessage(m);
}
}
La classe Message
non è eccitante - un contenuto String
e forse un timestamp.
Ciò di cui sto combattendo è come impaginare questo disegno e, si spera, rispondi ad alcune domande fastidiose che mi affliggono.
Supponendo che questo quadro sopra venga utilizzato in un servizio Web con più richieste in entrata:
-
Una richiesta web per pubblicare un messaggio in una stanza avrà solo l'ID della stanza. La ricerca (traduzione da
String roomId
- >Room room
) si verifica a livello web? O il metodo di servizio dovrebbe essere modificato per accettare l' ID della Stanza invece della Stanza stessa? -
Esiste una condizione di competizione nel metodo
postMessage()
in cui lo stato della stanza potrebbe cambiare tra il controllo e la pubblicazione effettiva del messaggio. Il livello di servizio è il posto giusto per la sincronizzazione? -
Preferisco che il servizio non debba sapere che tipo di gestore ha a che fare: se si tratta di un database, una soluzione in memoria, ecc. Dove deve essere determinata la sicurezza del thread, sul modello, manager, o livello di servizio? Se aggiungo
@Transactional
al livello di servizio, non sarà di aiuto quando si ha a che fare con un gestore in memoria. Tuttavia, l'aggiunta di una sorta di sincronizzazione basata su oggetti al servizio potrebbe impedire inutilmente più query di database (che altrimenti non sono correlate, ovvero la pubblicazione di due messaggi in due stanze separate) dall'esecuzione in parallelo. Ovviamente se abbiamo a che fare con una query di database, la sicurezza del thread a livello di modello è un punto controverso, poiché a meno che non ci occupiamo di una cache locale o di un gestore di modelli in memoria, è probabile che ottenga due istanze separate per stesso oggetto.
Sembrano domande abbastanza fondamentali, ma ho difficoltà a trovare libri, tutorial, discorsi, ecc. che rispondano a questo tipo di domande di progettazione di livello superiore. Capisco la concorrenza e i vari strumenti (chiusure di rientro, blocchi sincronizzati, ecc.) Ma metterli in pratica in modo sano e gestibile sembra essere un'attività fai-da-te.
Sperando che qualcuno possa aiutare a rispondere alle domande di cui sopra, o fornire alcune risorse che potrebbero aiutarmi a rispondere da solo.