> For the complete documentation index, see [llms.txt](https://mayanktyagi3111.gitbook.io/interview-prep/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://mayanktyagi3111.gitbook.io/interview-prep/lld-questions/file-storage-system/solution-2.md).

# Solution 2

Designing a **Google Drive-like file storage system** requires not only scalability and modularity but also the use of appropriate **design patterns** to ensure maintainability, flexibility, and performance.

***

### **Key Design Patterns Used**

| **Pattern**           | **Usage in File Storage System**                                                      |
| --------------------- | ------------------------------------------------------------------------------------- |
| **Singleton**         | Ensures a single instance of services like `AuthService` and `FileStorageService`.    |
| **Factory Pattern**   | Creates objects for different storage backends (Local, AWS S3, Google Cloud Storage). |
| **Strategy Pattern**  | Allows switching storage mechanisms dynamically (Local, Cloud, Distributed FS).       |
| **Observer Pattern**  | Notifies users when a file is shared with them.                                       |
| **Decorator Pattern** | Adds functionalities like **compression** and **encryption** to file storage.         |
| **Proxy Pattern**     | Restricts direct access to storage and adds logging/security.                         |
| **Builder Pattern**   | Constructs complex file metadata objects step by step.                                |

***

### **System Components & Patterns**

1. **File Metadata** (Builder Pattern)
2. **File Storage Service** (Strategy, Factory, Singleton)
3. **File Sharing Service** (Observer)
4. **Authentication Service** (Singleton)
5. **Access Proxy** (Proxy Pattern)
6. **Compression/Encryption for File Upload** (Decorator Pattern)

***

### **1. File Metadata (Builder Pattern)**

Used to construct complex metadata objects step by step.

```java
public class FileMetadata {
    private final String fileId;
    private final String fileName;
    private final String fileType;
    private final long fileSize;
    private final String ownerId;
    private final String storagePath;

    private FileMetadata(FileMetadataBuilder builder) {
        this.fileId = builder.fileId;
        this.fileName = builder.fileName;
        this.fileType = builder.fileType;
        this.fileSize = builder.fileSize;
        this.ownerId = builder.ownerId;
        this.storagePath = builder.storagePath;
    }

    public static class FileMetadataBuilder {
        private String fileId;
        private String fileName;
        private String fileType;
        private long fileSize;
        private String ownerId;
        private String storagePath;

        public FileMetadataBuilder setFileId(String fileId) {
            this.fileId = fileId;
            return this;
        }

        public FileMetadataBuilder setFileName(String fileName) {
            this.fileName = fileName;
            return this;
        }

        public FileMetadataBuilder setFileType(String fileType) {
            this.fileType = fileType;
            return this;
        }

        public FileMetadataBuilder setFileSize(long fileSize) {
            this.fileSize = fileSize;
            return this;
        }

        public FileMetadataBuilder setOwnerId(String ownerId) {
            this.ownerId = ownerId;
            return this;
        }

        public FileMetadataBuilder setStoragePath(String storagePath) {
            this.storagePath = storagePath;
            return this;
        }

        public FileMetadata build() {
            return new FileMetadata(this);
        }
    }
}
```

***

### **2. File Storage Service (Strategy + Factory + Singleton)**

* **Factory Pattern**: Creates storage service based on type (Local, AWS, Google Cloud).
* **Strategy Pattern**: Allows dynamic switching between storage mechanisms.
* **Singleton Pattern**: Ensures only one instance of `FileStorageService`.

```java
// Strategy Interface
public interface StorageStrategy {
    void storeFile(String fileName, byte[] data) throws IOException;
    byte[] retrieveFile(String fileName) throws IOException;
}

// Concrete Strategy 1: Local Storage
public class LocalStorageStrategy implements StorageStrategy {
    private static final String STORAGE_DIR = "local_storage/";

    @Override
    public void storeFile(String fileName, byte[] data) throws IOException {
        Files.write(Paths.get(STORAGE_DIR + fileName), data);
    }

    @Override
    public byte[] retrieveFile(String fileName) throws IOException {
        return Files.readAllBytes(Paths.get(STORAGE_DIR + fileName));
    }
}

// Concrete Strategy 2: Cloud Storage (AWS S3)
public class CloudStorageStrategy implements StorageStrategy {
    @Override
    public void storeFile(String fileName, byte[] data) {
        System.out.println("Uploading " + fileName + " to AWS S3...");
    }

    @Override
    public byte[] retrieveFile(String fileName) {
        System.out.println("Downloading " + fileName + " from AWS S3...");
        return new byte[0]; // Simulated response
    }
}

// Factory Pattern for Storage Selection
public class StorageFactory {
    public static StorageStrategy getStorageStrategy(String type) {
        if ("LOCAL".equalsIgnoreCase(type)) {
            return new LocalStorageStrategy();
        } else if ("CLOUD".equalsIgnoreCase(type)) {
            return new CloudStorageStrategy();
        }
        throw new IllegalArgumentException("Unknown storage type");
    }
}

// Singleton File Storage Service
public class FileStorageService {
    private static FileStorageService instance;
    private StorageStrategy storageStrategy;

    private FileStorageService(StorageStrategy strategy) {
        this.storageStrategy = strategy;
    }

    public static FileStorageService getInstance(StorageStrategy strategy) {
        if (instance == null) {
            instance = new FileStorageService(strategy);
        }
        return instance;
    }

    public void uploadFile(String fileName, byte[] data) throws IOException {
        storageStrategy.storeFile(fileName, data);
    }

    public byte[] downloadFile(String fileName) throws IOException {
        return storageStrategy.retrieveFile(fileName);
    }
}
```

***

### **3. File Sharing Service (Observer Pattern)**

Used to notify users when a file is shared.

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

interface Observer {
    void update(String message);
}

class User implements Observer {
    private String name;

    public User(String name) {
        this.name = name;
    }

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

class FileSharingService {
    private List<Observer> observers = new ArrayList<>();

    public void addObserver(Observer observer) {
        observers.add(observer);
    }

    public void shareFile(String fileId, String userName) {
        System.out.println("File " + fileId + " shared with " + userName);
        notifyObservers("File " + fileId + " shared with you.");
    }

    private void notifyObservers(String message) {
        for (Observer observer : observers) {
            observer.update(message);
        }
    }
}
```

***

### **4. Access Control (Proxy Pattern)**

Restricts unauthorized file access.

```java
interface FileAccess {
    void accessFile(String fileName, String userId);
}

class RealFileAccess implements FileAccess {
    @Override
    public void accessFile(String fileName, String userId) {
        System.out.println(userId + " is accessing " + fileName);
    }
}

class FileAccessProxy implements FileAccess {
    private RealFileAccess realFileAccess;
    private boolean isAuthenticated;

    public FileAccessProxy(boolean isAuthenticated) {
        this.realFileAccess = new RealFileAccess();
        this.isAuthenticated = isAuthenticated;
    }

    @Override
    public void accessFile(String fileName, String userId) {
        if (isAuthenticated) {
            realFileAccess.accessFile(fileName, userId);
        } else {
            System.out.println("Access Denied for " + userId);
        }
    }
}
```

***

### **Summary of Patterns Used**

* **Builder Pattern:** Constructs file metadata.
* **Strategy Pattern:** Supports multiple storage types.
* **Factory Pattern:** Creates different storage backends.
* **Singleton Pattern:** Ensures a single instance of services.
* **Observer Pattern:** Sends notifications when files are shared.
* **Proxy Pattern:** Restricts unauthorized file access.
* **Decorator Pattern:** Can be used for adding compression/encryption.
