Proxy Design Pattern
Problem​
You: Hi Shubh, recently I got a task from my manager. I've built a system where we can create employees in the database and also fetch the list of employees.
Shubh: Oh nice! You're making progress in your career. I hope your manager is happy with you! 😄
You: Haha, the task is not over yet. I need to restrict access to certain functionality.
Shubh: Which one?
You: The creation of a new employee. Only an admin should be able to create a new employee. I'm thinking of adding this logic in the createEmployee()
function itself.
Shubh: You could do that, but that wouldn't be a good idea! Your server should always focus on business logic. Let a proxy handle access-related stuff. You should use the Proxy Design Pattern.
You: Proxy Design Pattern? I haven't heard about it.
Shubh: The Proxy Pattern is used for various purposes like access control, caching, etc. We can create a dedicated proxy class to handle such scenarios.
UML​
Shubh: In this UML diagram:
-
ISubject
Interface: This is implemented by theRealSubject
. In our example,EmployeeDAO
is an interface implemented byEmployeeDAOImpl
. -
Proxy
isA
ISubject: This relationship is known as inheritance. It means the Proxy class knows all the functionalities that need to be implemented. -
Proxy
hasA
RealSubject: This relationship is known as association. It means the Proxy class can add certain logic, like access control, before calling the functionality of theRealSubject
. The client interacts with the proxy, which then adds additional logic before calling the real subject's functionality.
Code Implementation​
Employee Class​
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class Employee {
private String name;
private String id;
private Role role;
public Employee(String name, String id, Role role) {
this.name = name;
this.id = id;
this.role = role;
}
}
EmployeeDAO Interface​
public interface EmployeeDAO {
void createEmployee(Employee employee);
Employee getEmployee(String id);
}
EmployeeDAOImpl Class​
public class EmployeeDAOImpl implements EmployeeDAO {
@Override
public void createEmployee(Employee employee) {
System.out.println("Employee with name " + employee.getName() + " created");
}
@Override
public Employee getEmployee(String id) {
System.out.println("Fetching employee with id: " + id);
return new Employee("Shubh", "1", Role.ADMIN);
}
}
EmployeeDAOProxy Class​
public class EmployeeDAOProxy implements EmployeeDAO {
private EmployeeDAO employeeDAO;
EmployeeDAOProxy(EmployeeDAO employeeDAO) {
this.employeeDAO = employeeDAO;
}
@Override
public void createEmployee(Employee employee) {
if (employee.getRole() == Role.ADMIN) {
employeeDAO.createEmployee(employee);
} else {
System.out.println("ACCESS DENIED");
}
}
@Override
public Employee getEmployee(String id) {
return employeeDAO.getEmployee(id);
}
}
Role Enum​
public enum Role {
ADMIN, USER
}
Main Class (Client Code)​
public class Main {
public static void main(String[] args) {
EmployeeDAO employeeDAOProxy = new EmployeeDAOProxy(new EmployeeDAOImpl());
Employee employee1 = new Employee("Shubh", "1", Role.ADMIN);
Employee employee2 = new Employee("Kunal", "2", Role.USER);
System.out.println("------------------------------");
employeeDAOProxy.createEmployee(employee1);
employeeDAOProxy.getEmployee("1");
System.out.println("------------------------------");
employeeDAOProxy.createEmployee(employee2);
employeeDAOProxy.getEmployee("2");
}
}
Key Benefits of the Proxy Design Pattern​
Before watching, make sure you give it a try
-
Access Control: The Proxy can control access to the actual object. In our example, it restricts the creation of employees to admins only.
-
Logging and Auditing: Proxies can be used to add logging or auditing functionality before or after invoking methods on the RealSubject.