Hotline
0388011834
Trang chủ/ Góc lập trình/Design Patterns

Structural Patterns - Proxy



Khái niệm

Proxy Design Pattern là một mẫu thiết kế cấu trúc (Structural Pattern) giúp bạn tạo ra một sự thay thế cho một đối tượng khác. Nó kiểm soát việc truy cập tới đối tượng gốc, cho phép việc thực hiện thao tác nào đó trước hoặc sau khi tác động tới đối tượng gốc.

    1.  

Các thành phần chính

  • Service Interface: Là lớp giao diện dịch vụ mà proxy và dịch vụ phải tuân theo.
  • Service: Lớp cung cấp các logic nghiệp vụ.
  • Proxy: Lớp triển khai giao diện dịch vụ. Nó chứa một trường tham chiếu trỏ đến đối tượng dịch vụ. Thực hiện một vài xử lý của riêng nó trước khi gửi yêu cầu tới đối tượng dịch vụ.
  • Client: Sẽ làm việc với cả dịch vụ và proxy thông qua cùng giao diện.

Ưu điểm

  • Kiểm soát tốt quyền truy cập và bảo mật tới lớp dịch vụ.
  • Có thể điều khiển, quản lý vòng đời đối tượng dịch vụ mà không cần mã khách biết hoặc quan tâm tới.
  • Proxy vẫn duy trì hoạt động ngay cả khi đối tượng dịch vụ chưa sẵn sàng hoặc không khả dụng.
  • Nguyên tắc Mở/Đóng (Open/Closed Principle): Bạn có thể thêm những proxy mới mà không làm thay đổi lớp dịch vụ và mã khách.

Nhược điểm

  • Mã nguồn sẽ trở nên phức tạp vì việc cần phải tạo thêm nhiều lớp mới.
  • Phản hồi từ dịch vụ có thể bị chậm trễ nếu phải xử lý một lượng logic lớn.

Ví dụ thực tế

  • Bài toán

Giả sử ta có một ứng dụng đủ lớn (có thể gọi là ứng dụng cha), ta phải tạo một ứng dụng con (Microservice) để tiện cho việc quản lý và giảm bớt sự phức tạp ở ứng dụng ban đầu.

Quay về với bài toán quản lý nhà hàng mà tôi thường sử dụng trong các bài viết về mẫu thiết kế. Giờ đây tôi sẽ tạo ra một ứng dụng con để chứa các logic nghiệp vụ của tính năng bán đồ ăn. Và ứng dụng ban đầu của tôi sẽ có các giao diện phục vụ việc bán hàng.

Ứng dụng cha làm việc với ứng dụng con thông qua việc gọi API từ ứng dụng con.

Vấn đề phát sinh sẽ là: Ở ứng dụng cha cần thực hiện việc bán đồ ăn, lúc này sẽ cần gọi tới ứng dụng con để thực hiện các logic nghiệp vụ. Lúc này ở ứng dụng cha cần phải thực hiện một vài thao tác xác thực để làm sao thông báo cho ứng dụng con biết “đây là cha”, rồi sau đó mới thực hiện các logic nghiệp vụ được.

  • Phân tích bài toán

Bài toán dạng này rất phổ biến ở những ứng dụng lớn cần chia nhỏ thành các ứng dụng con để quản lý riêng biệt. Hoặc cũng thường gặp phải ở các ứng dụng cần tích hợp bên thứ ba.

Yêu cầu bài toán cũng khá rõ ràng, cha đang có việc cần con xử lý, nhưng để con biết đó đúng là cha thì mới xử lý và trả về kết quả cho cha.

  • Cách triển khai

Đầu tiên, ta sẽ tạo lớp giao diện dịch vụ. Lớp giao diện này sẽ khai báo một phương thức gửi yêu cầu để ứng dụng con và proxy thực hiện triển khai.

    public interface IDichVu
    {
        void GuiYeuCau();
    }

Và dưới đây sẽ là logic nghiệp vụ của ứng dụng con. Nó sẽ tuân theo giao diện dịch vụ.

    class UngDungCon : IDichVu
    {
        public void GuiYeuCau()
        {
            Console.WriteLine("UngDungCon: Dang xu ly yeu cau...");
        }
    }

Tiếp theo sẽ là việc triển khai của proxy. Nó cũng sẽ tuân theo giao diện dịch vụ.

    class UngDungConProxy : IDichVu
    {
        private UngDungCon _ungDungCon;

 
        public UngDungConProxy(UngDungCon ungDungCon)
        {
            this._ungDungCon = ungDungCon;
        }

 
        public void GuiYeuCau()
        {
            if (this.KiemTraTruyCap())
            {
                this._ungDungCon.GuiYeuCau();
            }
        }

 
        public bool KiemTraTruyCap()
        {
            Console.WriteLine("UngDungConProxy: Dang kiem tra truy cap truoc khi gui yeu cau toi UngDungCon...");

 
            return true;
        }
    }

Trong lớp proxy trên, ta sẽ khai báo một trường tham chiếu để trỏ đến dịch vụ (ứng dụng con). Và sẽ triển khai phương thức gửi yêu cầu để kiểm tra một vài điều kiện trước khi gửi yêu cầu tới ứng dụng con.

Cuối cùng là thành phần Client. Nó có nhiệm vụ thực thi gửi yêu cầu cho cả dịch vụ (ứng dụng con) và proxy.

    public class Client
    {
        public void ClientCode(IDichVu dichVu)
        {
            dichVu.GuiYeuCau();
        }
    }

Dưới đây sẽ là code hàm Main để mô phỏng việc gọi đến ứng dụng con thông qua proxy:

    class ClientProxy
    {
        public void Main()
        {
            Client client = new Client();

 
            Console.WriteLine("UngDungCha: Goi truc tiep toi ung dung con:");
            UngDungCon ungDungCon = new UngDungCon();
            client.ClientCode(ungDungCon);

 
            Console.WriteLine();

 
            Console.WriteLine("UngDungCha: Goi toi ung dung con thong qua proxy:");
            UngDungConProxy proxy = new UngDungConProxy(ungDungCon);
            client.ClientCode(proxy);
        }
    }

Kết quả sau khi chạy chương trình:

Như bạn thấy, thông qua việc gọi proxy thì sẽ cần thực hiện thêm hành động kiểm tra, nếu hợp lệ thì mới gọi tới ứng dụng con. Nó sẽ giúp việc tăng cường bảo mật và kiểm soát truy cập khi làm việc với các ứng dụng từ bên ngoài.

    1.  

Kết luận

Như vậy, qua bài viết này, tôi hi vọng các bạn sẽ nắm được khái niệm cũng như biết được việc khi nào thì nên áp dụng mẫu thiết kế Proxy vào trong ứng dụng của mình.

Ví dụ tôi đưa đôi khi không chính xác và thuyết phục hoàn toàn, rất mong sự góp ý từ phía các bạn để tôi có thể củng cố thêm kiến thức cho bản thân mình.