User: Represents a user in the system with unique credentials (e.g., phone number, username).
Message: Represents a chat message that includes the sender, receiver, timestamp, and message content.
ChatRoom: A chat room represents a group chat where multiple users can send and receive messages.
Real-time Communication: Facilitates real-time message delivery through sockets (WebSocket or similar).
User Authentication: Ensures secure login and message exchange with proper authentication.
Message Storage: Stores sent and received messages in a database.
Message Notifications: Users are notified in real-time when they receive a new message.
Design Patterns Used
Singleton Pattern: Used for managing the ChatRoomManager class that handles all chat rooms in the system.
Factory Pattern: Used for creating instances of Message and ChatRoom.
Observer Pattern: Used to notify users when a new message is received in real-time.
Command Pattern: Used to send and receive messages in the system.
Code Implementation
1. Singleton Pattern - ChatRoomManager Class
The Singleton Pattern ensures that there is only one instance of ChatRoomManager managing all active chat rooms.
import java.util.HashMap;
import java.util.Map;
// Singleton Pattern to manage active chat rooms
class ChatRoomManager {
private static ChatRoomManager instance;
private Map<String, ChatRoom> chatRooms;
private ChatRoomManager() {
chatRooms = new HashMap<>();
}
// Get the single instance of ChatRoomManager
public static ChatRoomManager getInstance() {
if (instance == null) {
instance = new ChatRoomManager();
}
return instance;
}
// Create a chat room
public ChatRoom createChatRoom(String roomName) {
if (!chatRooms.containsKey(roomName)) {
ChatRoom chatRoom = new ChatRoom(roomName);
chatRooms.put(roomName, chatRoom);
return chatRoom;
}
return null; // Chat room already exists
}
// Get a chat room
public ChatRoom getChatRoom(String roomName) {
return chatRooms.get(roomName);
}
}
2. Factory Pattern - MessageFactory Class
The Factory Pattern is used to create instances of messages.
// Factory Pattern to create different types of messages
class MessageFactory {
public static Message createMessage(String sender, String receiver, String content) {
return new Message(sender, receiver, content);
}
}
3. Observer Pattern - User Class (Observer)
The Observer Pattern is used to notify users when a new message is received in the chat room.
import java.util.ArrayList;
import java.util.List;
// Observer Pattern: User receives notifications of new messages
class User implements Observer {
private String username;
private List<ChatRoom> chatRooms;
public User(String username) {
this.username = username;
this.chatRooms = new ArrayList<>();
}
public String getUsername() {
return username;
}
// Subscribe user to a chat room
public void joinChatRoom(ChatRoom chatRoom) {
chatRoom.addObserver(this);
chatRooms.add(chatRoom);
}
// Receive notification about new messages
@Override
public void update(String message) {
System.out.println(username + " received message: " + message);
}
// Unsubscribe from a chat room
public void leaveChatRoom(ChatRoom chatRoom) {
chatRoom.removeObserver(this);
chatRooms.remove(chatRoom);
}
}
4. Command Pattern - MessageCommand Class
The Command Pattern is used to encapsulate the message sending action.
// Command Pattern to send a message
interface Command {
void execute();
}
class MessageCommand implements Command {
private Message message;
private ChatRoom chatRoom;
public MessageCommand(ChatRoom chatRoom, Message message) {
this.chatRoom = chatRoom;
this.message = message;
}
@Override
public void execute() {
chatRoom.sendMessage(message); // Send message to the chat room
}
}
5. Chat Room Class
The ChatRoom class contains the logic for managing users and sending messages. This uses the Observer Pattern to notify all users when a message is sent.
import java.util.ArrayList;
import java.util.List;
// Chat Room class to manage users and messages
class ChatRoom {
private String roomName;
private List<Observer> observers;
private List<Message> messageHistory;
public ChatRoom(String roomName) {
this.roomName = roomName;
this.observers = new ArrayList<>();
this.messageHistory = new ArrayList<>();
}
public String getRoomName() {
return roomName;
}
// Add observer (user)
public void addObserver(Observer observer) {
observers.add(observer);
}
// Remove observer (user)
public void removeObserver(Observer observer) {
observers.remove(observer);
}
// Send message to all users in the chat room
public void sendMessage(Message message) {
messageHistory.add(message);
for (Observer observer : observers) {
observer.update(message.getContent()); // Notify all users
}
}
// Retrieve message history
public List<Message> getMessageHistory() {
return messageHistory;
}
}
6. Message Class
The Message class holds the details of a message including the sender, receiver, content, and timestamp.
import java.time.LocalDateTime;
// Message class representing a chat message
class Message {
private String sender;
private String receiver;
private String content;
private LocalDateTime timestamp;
public Message(String sender, String receiver, String content) {
this.sender = sender;
this.receiver = receiver;
this.content = content;
this.timestamp = LocalDateTime.now();
}
public String getSender() {
return sender;
}
public String getReceiver() {
return receiver;
}
public String getContent() {
return content;
}
public LocalDateTime getTimestamp() {
return timestamp;
}
}
7. Observer Interface
The Observer interface ensures that the User class can receive updates from the ChatRoom.
For user authentication, we can use a secure system based on usernames and passwords. For simplicity, here’s an example of the AuthService class that could handle user authentication.
import java.util.HashMap;
import java.util.Map;
class AuthService {
private static final Map<String, String> userCredentials = new HashMap<>(); // Simple in-memory credential storage
static {
// Example credentials
userCredentials.put("user1", "password1");
userCredentials.put("user2", "password2");
}
// Authenticate user
public static boolean authenticate(String username, String password) {
String storedPassword = userCredentials.get(username);
return storedPassword != null && storedPassword.equals(password);
}
}
Testing the System
Below is a simple example to test the chat system with two users, a chat room, and message sending/receiving.
public class Main {
public static void main(String[] args) {
// Create instances of users
User user1 = new User("user1");
User user2 = new User("user2");
// Create a chat room
ChatRoomManager chatRoomManager = ChatRoomManager.getInstance();
ChatRoom chatRoom = chatRoomManager.createChatRoom("Friends");
// Users join the chat room
user1.joinChatRoom(chatRoom);
user2.joinChatRoom(chatRoom);
// Send a message
Message message = MessageFactory.createMessage("user1", "user2", "Hello, how are you?");
Command messageCommand = new MessageCommand(chatRoom, message);
messageCommand.execute(); // Send message
// Receive message (via observer pattern)
user2.update("Hello, how are you?");
// User2 sends a reply
Message reply = MessageFactory.createMessage("user2", "user1", "I'm good, thanks!");
messageCommand = new MessageCommand(chatRoom, reply);
messageCommand.execute(); // Send reply
// User1 receives the reply
user1.update("I'm good, thanks!");
}
}
Summary of Design Patterns Used
Singleton Pattern: Used in the ChatRoomManager class to ensure a single instance that manages all chat rooms in the system.
Factory Pattern: Used in MessageFactory to create new Message objects.
Observer Pattern: Used to notify all subscribed users (observers) in a chat room when a new message is sent.
Command Pattern: Used to encapsulate message sending actions, allowing easy message execution.
Conclusion
This low-level design of a chat application uses design patterns to create a modular, scalable system that supports real-time messaging, secure user authentication, and efficient chat room management. The use of patterns like Singleton, Factory, Observer, and Command ensures a clean and maintainable architecture while allowing easy extensions like adding multimedia messages or integrating with external chat services.