📂
Interview Prep
LLD Questions
LLD Questions
  • LLD Introduction
  • Meeting Scheduler
  • Distributed Cache System
  • Rate limiter
  • Multi-Tier Elevator System
  • MyGate System
  • Uber Sytem LLD
  • Parking Lot System
  • Online book store
  • Library Management System
  • Movie Ticket Booking System
  • Hotel Management System
  • File Storage System
    • Solution 2
  • Chat Application
  • Social Media Platform
  • Notification System
  • Airline Reservation System
  • ATM System
  • E-commerce Website
  • Food Delivery System
  • Shopping Cart System
  • URL Shortener system
  • Chess Tournament System
  • Threading therory
  • OOP questions
Powered by GitBook
On this page

File Storage System

Entities and Relationships

In a file storage system, we have several key entities:

  1. File: Represents a file with its name, size, metadata, versions, and permissions.

  2. User: Represents a user interacting with the file system.

  3. FileVersion: Represents different versions of a file.

  4. FileMetadata: Stores metadata information about the file (e.g., size, created date).

  5. Permission: Represents user permissions (read/write/share) for a file.

  6. StorageStrategy: Represents different storage mechanisms (e.g., local storage, cloud storage).

  7. FileSystem: Manages all file operations and ensures that only one instance exists, implementing Singleton.

  8. NotificationSystem: Notifies users of file changes, utilizing Observer Pattern.

Design Patterns Used

  • Singleton Pattern: Used in the FileSystem class to ensure a single instance manages file operations.

  • Factory Pattern: Used in FileFactory to create instances of files and file versions.

  • Strategy Pattern: Used to switch between different storage strategies (local or cloud).

  • Observer Pattern: Used in the NotificationSystem to notify users of changes or updates to files.


Code Implementation


1. Singleton Pattern - FileSystem Class

The Singleton Pattern ensures only one instance of FileSystem exists in the application.

import java.util.List;
import java.util.ArrayList;

// Singleton pattern for FileSystem to manage file operations
class FileSystem {
    private static FileSystem instance;
    private List<File> files;
    private StorageStrategy storageStrategy;

    private FileSystem(StorageStrategy storageStrategy) {
        this.files = new ArrayList<>();
        this.storageStrategy = storageStrategy;
    }

    public static FileSystem getInstance(StorageStrategy storageStrategy) {
        if (instance == null) {
            instance = new FileSystem(storageStrategy);
        }
        return instance;
    }

    public void addFile(File file) {
        files.add(file);
        storageStrategy.uploadFile(file); // Delegate file storage to strategy
    }

    public boolean downloadFile(File file) {
        return storageStrategy.downloadFile(file); // Delegate file download to strategy
    }
}

2. Factory Pattern - FileFactory Class

The Factory Pattern abstracts the creation of File and FileVersion objects.

// Factory pattern to create File and FileVersion
class FileFactory {

    public static File createFile(String fileName, long fileSize, User owner) {
        return new File(fileName, fileSize, owner);
    }

    public static FileVersion createFileVersion(String versionId, byte[] content) {
        return new FileVersion(versionId, content);
    }
}

3. Strategy Pattern - StorageStrategy and Concrete Implementations (LocalStorage, CloudStorage)

The Strategy Pattern allows dynamic switching between storage mechanisms.

// Strategy pattern to define storage types
interface StorageStrategy {
    boolean uploadFile(File file);
    boolean downloadFile(File file);
}

// Concrete strategy for local storage
class LocalStorage implements StorageStrategy {
    @Override
    public boolean uploadFile(File file) {
        System.out.println("Uploading file to local storage: " + file.getFileName());
        return true;
    }

    @Override
    public boolean downloadFile(File file) {
        System.out.println("Downloading file from local storage: " + file.getFileName());
        return true;
    }
}

// Concrete strategy for cloud storage
class CloudStorage implements StorageStrategy {
    @Override
    public boolean uploadFile(File file) {
        System.out.println("Uploading file to cloud storage: " + file.getFileName());
        return true;
    }

    @Override
    public boolean downloadFile(File file) {
        System.out.println("Downloading file from cloud storage: " + file.getFileName());
        return true;
    }
}

4. Observer Pattern - NotificationSystem and FileObserver

The Observer Pattern is used to notify users of changes (like updates or sharing) in the files.

import java.util.ArrayList;
import java.util.List;

// Observer pattern
interface Observer {
    void update(String message);
}

class NotificationSystem implements Observer {
    private String userName;

    public NotificationSystem(String userName) {
        this.userName = userName;
    }

    @Override
    public void update(String message) {
        System.out.println(userName + " received notification: " + message);
    }
}

class File {
    private String fileName;
    private long fileSize;
    private User owner;
    private List<FileVersion> versions;
    private List<Observer> observers; // To notify users when file is updated
    private FileMetadata metadata;

    public File(String fileName, long fileSize, User owner) {
        this.fileName = fileName;
        this.fileSize = fileSize;
        this.owner = owner;
        this.versions = new ArrayList<>();
        this.observers = new ArrayList<>();
        this.metadata = new FileMetadata(fileName, owner);
    }

    // Add new version of the file
    public void addVersion(FileVersion version) {
        versions.add(version);
    }

    // Register observers for notifications
    public void addObserver(Observer observer) {
        observers.add(observer);
    }

    // Update file and notify observers
    public void updateFile(String newVersion) {
        System.out.println("File " + fileName + " has been updated to version " + newVersion);
        for (Observer observer : observers) {
            observer.update("File " + fileName + " has been updated.");
        }
    }

    // Getter methods
    public String getFileName() {
        return fileName;
    }

    public long getFileSize() {
        return fileSize;
    }

    public User getOwner() {
        return owner;
    }

    public List<FileVersion> getVersions() {
        return versions;
    }
}

5. File Class, Versioning, Permissions, and Other Entities

These are the key entities involved in the file storage system. They represent user-related data and metadata for file management.

// User class to represent users in the system
class User {
    private String userName;
    private String email;

    public User(String userName, String email) {
        this.userName = userName;
        this.email = email;
    }

    public String getUserName() {
        return userName;
    }

    public String getEmail() {
        return email;
    }
}

// FileVersion class to represent versions of a file
class FileVersion {
    private String versionId;
    private byte[] content;

    public FileVersion(String versionId, byte[] content) {
        this.versionId = versionId;
        this.content = content;
    }

    public String getVersionId() {
        return versionId;
    }

    public byte[] getContent() {
        return content;
    }
}

// Metadata class to store file-related metadata
class FileMetadata {
    private String fileName;
    private User owner;
    private long createdAt;

    public FileMetadata(String fileName, User owner) {
        this.fileName = fileName;
        this.owner = owner;
        this.createdAt = System.currentTimeMillis(); // Current timestamp
    }

    public String getFileName() {
        return fileName;
    }

    public User getOwner() {
        return owner;
    }

    public long getCreatedAt() {
        return createdAt;
    }
}

Testing the System

In this test scenario, we create instances of users and files, perform operations like adding files, updating versions, and downloading files while notifying users of changes.

public class Main {
    public static void main(String[] args) {
        // Using Singleton pattern for FileSystem
        StorageStrategy cloudStorage = new CloudStorage();
        FileSystem fileSystem = FileSystem.getInstance(cloudStorage);

        // Create users and files
        User user1 = new User("John", "john@example.com");
        User user2 = new User("Alice", "alice@example.com");

        File file1 = FileFactory.createFile("report.pdf", 1024, user1);
        FileVersion version1 = FileFactory.createFileVersion("v1", new byte[1024]);
        file1.addVersion(version1);

        // Add observers
        NotificationSystem observer1 = new NotificationSystem(user1.getUserName());
        file1.addObserver(observer1);

        // Add file to the file system
        fileSystem.addFile(file1);

        // Update file
        file1.updateFile("v2");

        // Download file
        fileSystem.downloadFile(file1);
    }
}

Summary of Design Patterns Implemented

  1. Singleton Pattern: Ensures that only one instance of the FileSystem class exists, managing the centralized file operations.

  2. Factory Pattern: Provides a simple interface for creating File and FileVersion objects, abstracting the object creation logic.

  3. Strategy Pattern: Enables the dynamic switching between LocalStorage and CloudStorage without modifying the core logic.

  4. Observer Pattern: Notifies users (observers) when a file is updated, enhancing the interactivity and responsiveness of the system.

Conclusion

This low-level design provides a flexible, scalable, and modular structure for a file storage system. By utilizing design patterns, we ensure that the system is easy to maintain and extend, while also providing flexibility in storage solutions, file versioning, and user notifications.

PreviousHotel Management SystemNextSolution 2

Last updated 3 months ago