1. What (Proxy Pattern là gì?)

Proxy Pattern là một mẫu thiết kế thuộc nhóm Structural Design Patterns (mẫu thiết kế cấu trúc), trong đó một đối tượng đại diện (proxy) kiểm soát việc truy cập đến một đối tượng thực (real object). Proxy thường được sử dụng để kiểm soát, tối ưu hoặc quản lý việc truy cập đến tài nguyên đắt đỏ hoặc nhạy cảm.

Proxy cung cấp một lớp bọc xung quanh đối tượng thực, cho phép thêm các hành vi mới trước hoặc sau khi tương tác với đối tượng này mà không thay đổi mã nguồn của đối tượng thực.

2. Why (Tại sao nên dùng Proxy Pattern?)

  • Kiểm soát truy cập: Giúp kiểm soát việc truy cập vào đối tượng thực, đặc biệt là khi đối tượng đó có quá trình khởi tạo hoặc sử dụng tốn kém tài nguyên.
  • Tăng tính bảo mật: Proxy có thể giới hạn hoặc xác thực các yêu cầu trước khi đối tượng thực được sử dụng.
  • Tăng hiệu suất: Giảm tải đối với đối tượng thực bằng cách thực hiện các hành động như caching (lưu trữ tạm thời) hoặc lazy initialization (khởi tạo khi cần thiết).
  • Đóng gói logic bổ sung: Proxy cho phép chèn thêm các thao tác như logging, quản lý giao dịch hoặc kiểm tra quyền mà không làm thay đổi đối tượng thực.

3. When (Khi nào nên sử dụng Proxy Pattern?)

  • Khi cần kiểm soát truy cập đến một đối tượng hoặc một hệ thống.
  • Khi cần tối ưu hóa hiệu suất bằng cách giảm thiểu tải tài nguyên (caching hoặc lazy loading).
  • Khi muốn bổ sung các thao tác khác (như logging, kiểm tra bảo mật) mà không làm thay đổi đối tượng chính.
  • Khi đối tượng thực quá nặng nề để khởi tạo hoặc cần thực hiện các thao tác từ xa (Remote Proxy).

4. How (Cách sử dụng Proxy Pattern trong Java)

Proxy Pattern có thể được triển khai theo nhiều cách, bao gồm Static Proxy (Proxy tĩnh) và Dynamic Proxy (Proxy động).

Static Proxy: Bạn tự tạo một lớp Proxy triển khai giao diện của đối tượng thực. Lớp này chứa logic kiểm soát và gọi đến đối tượng thực.
Dynamic Proxy: Sử dụng các thư viện như Java Reflection hoặc CGLIB để tạo Proxy tự động tại runtime mà không cần tạo lớp proxy cụ thể.
Cấu trúc triển khai Proxy Pattern:

  • Interface (Subject): Định nghĩa giao diện chung cho Proxy và Real Object.
  • Real Object: Đối tượng thực hiện hành vi chính.
  • Proxy Object: Lớp đại diện, điều khiển truy cập đến đối tượng thực.

5. Ví dụ thực tế: Xem video trên YouTube thông qua Proxy

Giả sử bạn muốn xem video YouTube, nhưng một số video bị giới hạn ở quốc gia của bạn. Để xem được video này, bạn cần dùng Proxy để vượt qua giới hạn địa lý, bởi proxy sẽ giúp chuyển tiếp yêu cầu từ quốc gia khác mà video được phép phát

Bước 1: Tạo Interface (Subject)
Interface này sẽ được cả lớp Proxy và lớp đối tượng thực (Real Object) triển khai.

public interface YouTubeService {
    void playVideo(String videoId);
}

Bước 2: Tạo lớp đối tượng thực (Real Object)
Lớp này sẽ thực sự xử lý việc phát video.

public class RealYouTubeService implements YouTubeService {
    @Override
    public void playVideo(String videoId) {
        System.out.println("Playing video with ID: " + videoId);
    }
}

Bước 3: Tạo lớp Proxy để kiểm soát quyền truy cập
Proxy này sẽ kiểm tra xem bạn có thể truy cập video hay không dựa trên quốc gia của bạn.

public class YouTubeProxy implements YouTubeService {
    private RealYouTubeService realYouTubeService = new RealYouTubeService();
    private String userLocation;

    public YouTubeProxy(String userLocation) {
        this.userLocation = userLocation;
    }

    @Override
    public void playVideo(String videoId) {
        if (isBlocked(videoId)) {
            System.out.println("Video is blocked in your country: " + userLocation);
        } else {
            realYouTubeService.playVideo(videoId);
        }
    }

    private boolean isBlocked(String videoId) {
        // Giả lập kiểm tra video bị chặn
        return !userLocation.equals("Vietnam") && videoId.equals("Làm chủ công nghệ với Techmaster");
    }
}

Bước 4: Sử dụng Proxy để xem video

public class ProxyPatternDemo {
    public static void main(String[] args) {
        YouTubeService userInVietnam = new YouTubeProxy("Vietnam");
        YouTubeService userInUSA = new YouTubeProxy("USA");

        System.out.println("User in USA:");
        userInVietnam.playVideo("Làm chủ công nghệ với Techmaster");  // Video bị chặn

        System.out.println("\nUser in Vietnam:");
        userInUSA.playVideo("Làm chủ công nghệ với Techmaster");  // Video không bị chặn
    }
}

Kết quả:

User in Vietnam:
Video is blocked in your country: Vietnam

User in USA:
Playing video with ID: Check var sao kê MTTQ =]]