> 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.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://mayanktyagi3111.gitbook.io/interview-prep/lld-questions/file-storage-system/solution-2.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
