Low-Level Design (LLD) for an Application like MyGate
In this low-level design (LLD) for an application like MyGate (a popular building security system application), we will focus on core functionality such as visitor management, access control, notifications, and user authentication. We'll implement a series of classes to handle these features efficiently and use design patterns where necessary.
We will also discuss the following key questions for designing the system:
Entities and Relationships: What are the entities involved in this application? How do they relate to each other?
Authentication & Authorization: How will we authenticate users and authorize their access?
Visitor Management: How will visitors request entry, and how will the building security handle this?
Notification System: How will notifications be sent to users and security staff about visitors?
Access Control: How will the system manage access permissions based on roles (e.g., admin, security guard, resident)?
Key Components
User Management: For managing residents, security, and admin users.
Visitor Management: To handle requests from visitors for entry into the building.
Access Control: Determines whether a visitor or resident should be allowed into the building.
Notification System: Sends notifications to users and security guards.
Authentication: Ensures only authorized users can access the system and perform specific actions.
We will use the following design patterns:
Factory Pattern: To create instances of users, roles, and notifications dynamically.
Strategy Pattern: For different access control strategies.
Observer Pattern: For notification system to alert users and security guards when events occur.
Command Pattern: For handling and executing user actions (e.g., requesting entry).
Classes and Data Structures
1. User Class (Abstract Class)
The User class represents common properties and behaviors of all users (residents, admins, security personnel).
abstract class User {
protected String name;
protected String role;
public User(String name, String role) {
this.name = name;
this.role = role;
}
public abstract void performAction();
}
class Resident extends User {
public Resident(String name) {
super(name, "Resident");
}
@Override
public void performAction() {
System.out.println(name + " (Resident) can access the building.");
}
}
class Admin extends User {
public Admin(String name) {
super(name, "Admin");
}
@Override
public void performAction() {
System.out.println(name + " (Admin) can manage the system.");
}
}
class SecurityGuard extends User {
public SecurityGuard(String name) {
super(name, "SecurityGuard");
}
@Override
public void performAction() {
System.out.println(name + " (Security Guard) is monitoring the access.");
}
}
2. UserFactory Class (Factory Pattern)
The UserFactory class implements the Factory Pattern to create instances of different types of users.
class UserFactory {
public static User createUser(String type, String name) {
switch (type) {
case "Resident":
return new Resident(name);
case "Admin":
return new Admin(name);
case "SecurityGuard":
return new SecurityGuard(name);
default:
throw new IllegalArgumentException("Invalid user type");
}
}
}
3. Visitor Class
The Visitor class represents a visitor's details.
class Visitor {
private String name;
private String visitingPerson;
private boolean isAllowedEntry;
public Visitor(String name, String visitingPerson) {
this.name = name;
this.visitingPerson = visitingPerson;
this.isAllowedEntry = false; // Default: No entry
}
public String getName() {
return name;
}
public String getVisitingPerson() {
return visitingPerson;
}
public boolean isAllowedEntry() {
return isAllowedEntry;
}
public void setAllowedEntry(boolean isAllowed) {
this.isAllowedEntry = isAllowed;
}
}
4. AccessControlStrategy Interface and Implementations (Strategy Pattern)
The AccessControlStrategy interface defines the access control strategy, and we will implement various strategies.
interface AccessControlStrategy {
boolean authorizeEntry(Visitor visitor, User user);
}
class SecurityCheckStrategy implements AccessControlStrategy {
@Override
public boolean authorizeEntry(Visitor visitor, User user) {
// Allow entry only if the visitor is expected by the resident or admin
return visitor.getVisitingPerson().equals(user.name);
}
}
class AdminApprovalStrategy implements AccessControlStrategy {
@Override
public boolean authorizeEntry(Visitor visitor, User user) {
// Admin has the power to approve or reject visitor entry
return user instanceof Admin;
}
}
5. AccessControl Class
The AccessControl class manages the access control logic and selects the appropriate strategy.
class AccessControl {
private AccessControlStrategy strategy;
public AccessControl(AccessControlStrategy strategy) {
this.strategy = strategy;
}
public void setStrategy(AccessControlStrategy strategy) {
this.strategy = strategy;
}
public boolean requestEntry(Visitor visitor, User user) {
return strategy.authorizeEntry(visitor, user);
}
}
6. Notification System (Observer Pattern)
The Notification system is responsible for sending notifications to users when specific events happen, such as when a visitor arrives.
interface Observer {
void update(String message);
}
class SecurityGuardObserver implements Observer {
private String name;
public SecurityGuardObserver(String name) {
this.name = name;
}
@Override
public void update(String message) {
System.out.println("Security Guard " + name + ": " + message);
}
}
class ResidentObserver implements Observer {
private String name;
public ResidentObserver(String name) {
this.name = name;
}
@Override
public void update(String message) {
System.out.println("Resident " + name + ": " + message);
}
}
class NotificationSystem {
private List<Observer> observers = new ArrayList<>();
public void addObserver(Observer observer) {
observers.add(observer);
}
public void notifyObservers(String message) {
for (Observer observer : observers) {
observer.update(message);
}
}
}
7. Command Pattern for Request Handling
The Command Pattern allows actions (e.g., granting or rejecting entry) to be encapsulated in command objects.
interface Command {
void execute();
}
class GrantEntryCommand implements Command {
private AccessControl accessControl;
private Visitor visitor;
private User user;
public GrantEntryCommand(AccessControl accessControl, Visitor visitor, User user) {
this.accessControl = accessControl;
this.visitor = visitor;
this.user = user;
}
@Override
public void execute() {
if (accessControl.requestEntry(visitor, user)) {
visitor.setAllowedEntry(true);
System.out.println("Visitor " + visitor.getName() + " is granted entry.");
} else {
visitor.setAllowedEntry(false);
System.out.println("Visitor " + visitor.getName() + " is denied entry.");
}
}
}
Main Class to Demonstrate the System
public class MyGateSystem {
public static void main(String[] args) {
// Create users using the factory
User resident = UserFactory.createUser("Resident", "John");
User admin = UserFactory.createUser("Admin", "Alice");
User securityGuard = UserFactory.createUser("SecurityGuard", "Bob");
// Create a visitor
Visitor visitor = new Visitor("Mark", "John");
// Set up the notification system
NotificationSystem notificationSystem = new NotificationSystem();
notificationSystem.addObserver(new ResidentObserver("John"));
notificationSystem.addObserver(new SecurityGuardObserver("Bob"));
// Set the access control strategy to "SecurityCheckStrategy"
AccessControl accessControl = new AccessControl(new SecurityCheckStrategy());
// Create a command to grant entry to the visitor
Command grantEntryCommand = new GrantEntryCommand(accessControl, visitor, resident);
// Execute the command
grantEntryCommand.execute();
// Notify relevant users
notificationSystem.notifyObservers("Visitor " + visitor.getName() + " attempted entry.");
}
}
Explanation of Design Patterns Used
Factory Pattern:
The UserFactory class allows for the dynamic creation of users (Residents, Admins, and Security Guards) based on input type.
Strategy Pattern:
The AccessControlStrategy interface and its implementations (SecurityCheckStrategy, AdminApprovalStrategy) allow the access control mechanism to change behavior based on the selected strategy.
Observer Pattern:
The NotificationSystem uses the Observer pattern to notify relevant users (residents and security guards) when important events, such as a visitor requesting entry, occur.
Command Pattern:
The Command interface and the GrantEntryCommand encapsulate the logic for granting or rejecting visitor entry, allowing the action to be executed at a later time, enhancing the flexibility of the system.
Conclusion
The Low-Level Design of the MyGate Application efficiently handles user management, visitor entry, access control, notifications, and requests. By using design patterns such as Factory Pattern, Strategy Pattern, Observer Pattern, and Command Pattern, the system is both flexible and extensible. Future changes, such as adding new access control strategies, user types, or notification methods, can be done with minimal impact on existing code. This design offers a clean and modular solution to building a real-world gate management system.