problemhardood

Object-Oriented Design for Online Chat Server

HardUpdated: Jan 1, 2026

1. Problem Statement

Design an online chat server that supports users exchanging messages directly or via sessions (chat rooms). Keep the design minimal and focus on clean class responsibilities and simple message distribution.

Core goals:

  • Represent users and messages with essential metadata (sender, timestamp)
  • Support sessions where participants join, send, and receive messages
  • Allow clients to subscribe/unsubscribe to message streams
  • Keep delivery loosely coupled (observer or simple broker)

2. System Requirements

Functional Requirements:

  • Users and messages with timestamps and optional metadata
  • Sessions (chat rooms) supporting join/leave and message broadcast
  • Registration/unregistration of listeners (clients) that receive messages
  • Send/receive APIs for publishing and consuming messages

Non-Functional Requirements:

  • Concurrency: many users/sessions; low-latency delivery
  • Scalability: handle high fan-out; pluggable broker if needed
  • Durability/Retention: optional message TTL and trimming
  • Loose coupling between producers and consumers

Constraints/Edge Cases:

  • Large fan-out where synchronous notifications are expensive
  • Message ordering and delivery semantics (at-most/at-least-once) left as implementation detail

3. Use Case Diagram

Actors: User (client), Admin (optional), Chat System

graph TB
        subgraph "Chat System"
                UC1["Send Message"]
                UC2["Receive Message"]
                UC3["Join Session"]
                UC4["Leave Session"]
        end
        User([User])
        Admin([Admin])
        User --> UC1
        User --> UC2
        User --> UC3
        User --> UC4
        Admin --> UC3
        style User fill:#4CAF50,color:#fff
        style Admin fill:#FF9800,color:#fff

4. Class Diagram

Core Classes:

  • User: identifier and nickname
  • Message: interface defining value, timestamp, sender
  • SimpleMessage: concrete message
  • ChatListener: observer interface for message notifications
  • ChatWindow: client-side listener storing received messages
  • ChatSession: manages listeners; publishes incoming messages
  • (Optional) ChatServer/Broker: distribution layer (not implemented here)
classDiagram
        class User {
                +Long userId
                +String nickname
                +getUserId()
                +getNickname()
        }

        class Message {
                <<interface>>
                +String getValue()
                +void setValue(String)
                +Date getTimestamp()
                +void setTimestamp(Date)
                +User getUser()
        }

        class SimpleMessage {
                +String value
                +User user
                +Date timestamp
        }

        class ChatListener {
                <<interface>>
                +void notify(Message)
        }

        class ChatWindow {
                +User user
                +List~Message~ messageList
                +void notify(Message)
        }

        class ChatSession {
                +List~ChatListener~ registeredChatListeners
                +void register(ChatListener)
                +void incomingMessage(Message)
                +void publish(Message)
        }

        ChatSession "1" -- "0..*" ChatListener : registers
        ChatWindow ..|> ChatListener
        SimpleMessage ..> User : sender

5. Activity Diagrams

Send Message

graph TB
        U[User types message] --> S[Client sends to ChatSession]
        S --> V[Validate/enqueue]
        V --> P[Publish to registered listeners]
        P --> L[Listeners deliver/store]

Subscribe Listener

graph TB
        U[Client requests subscribe] --> R[ChatSession register listener]
        R --> A[Add to registered list]
        A --> OK[Return success]

6. Java Implementation

import java.util.*;
import java.util.Date;

// User.java
public class User {
        private Long userId;
        private String nickname;

        public User(Long userId, String nickname) {
                this.userId = userId;
                this.nickname = nickname;
        }

        public Long getUserId() { return userId; }
        public String getNickname() { return nickname; }
}

// Message.java
public interface Message {
        String getValue();
        void setValue(String value);
        Date getTimestamp();
        void setTimestamp(Date ts);
        User getUser();
}

// SimpleMessage.java
public class SimpleMessage implements Message {
        private String value;
        private User user;
        private Date timestamp;

        public SimpleMessage(String value, User user) {
                this.value = value;
                this.user = user;
                this.timestamp = new Date();
        }

        public String getValue() { return value; }
        public void setValue(String value) { this.value = value; }
        public Date getTimestamp() { return timestamp; }
        public void setTimestamp(Date ts) { this.timestamp = ts; }
        public User getUser() { return user; }
}

// ChatListener.java
public interface ChatListener {
        void notify(Message newMessage);
}

// ChatWindow.java (client-side listener)
public class ChatWindow implements ChatListener {
        private User user;
        private List<Message> messageList = new ArrayList<>();

        public ChatWindow(User user) { this.user = user; }

        public void notify(Message newMessage) {
                messageList.add(newMessage);
        }
}

// ChatSession.java
public class ChatSession {
        private List<ChatListener> registeredChatListeners = new ArrayList<>();

        public void register(ChatListener listener) {
                registeredChatListeners.add(listener);
        }

        public void incomingMessage(Message message) {
                publish(message);
        }

        protected void publish(Message messageToPublish) {
                for (ChatListener eachListener : registeredChatListeners) {
                        eachListener.notify(messageToPublish);
                }
        }
}

7. Python Implementation

from __future__ import annotations
from dataclasses import dataclass, field
from typing import List, Protocol
from datetime import datetime

@dataclass
class User:
        user_id: int
        nickname: str

class Message(Protocol):
        def get_value(self) -> str: ...
        def set_value(self, value: str) -> None: ...
        def get_timestamp(self) -> datetime: ...
        def get_user(self) -> User: ...

@dataclass
class SimpleMessage:
        value: str
        user: User
        timestamp: datetime = field(default_factory=datetime.now)

class ChatListener(Protocol):
        def notify(self, message: Message) -> None: ...

class ChatWindow:
        def __init__(self, user: User) -> None:
                self.user = user
                self.message_list: List[Message] = []

        def notify(self, message: Message) -> None:
                self.message_list.append(message)

class ChatSession:
        def __init__(self) -> None:
                self.registered_listeners: List[ChatListener] = []

        def register(self, listener: ChatListener) -> None:
                self.registered_listeners.append(listener)

        def incoming_message(self, message: Message) -> None:
                self.publish(message)

        def publish(self, message: Message) -> None:
                for listener in self.registered_listeners:
                        listener.notify(message)

Comments