Mẫu thiết kế Proxy – kiểm soát truy xuất object

0

Mẫu thiết kế Proxy thuộc nhóm structural có khả năng kiểm soát việc tạo và truy xuất object. Proxy thường là một object nhỏ đơn giản nằm giữa client code và object thật (phức tạp hơn) nhằm kiểm soát truy xuất vào object thực. Khi điều kiện phù hợp, proxy sẽ chuyển (delegate) yêu cầu của client sang object thực để xử lý.

Mẫu thiết kế Proxy là gì

Hãy tưởng tượng tới bộ phận một cửa ở các cơ quan công quyền (như ở phường). Mặc dù ở phường có rất nhiều người phụ trách các mảng công việc khác nhau, bộ phận một cửa là nơi duy nhất người dân tiếp xúc.

Bộ phận này tiếp nhận mọi yêu cầu của người dân và thực hiện kiểm tra các giấy tờ liên quan. Nếu giấy tờ đầy đủ và phù hợp, bộ phận một cửa sẽ chuyển giấy tờ đến người phụ trách đúng mảng công việc đó để giải quyết. Nếu chưa đầy đủ hoặc giấy tờ có lỗi, bộ phận một cửa sẽ trả lại và yêu cầu thực hiện đầy đủ trước khi tiếp nhận.

Vậy mô hình này có gì tốt. Hãy hiểu rằng, việc xử lý mỗi công việc theo yêu cầu của người dân không hề đơn giản. Nó tốn thời gian và công sức. Nếu mọi việc ngay lập tức chuyển đến bộ phận chuyên trách ngay lập tức, họ có thể phải thực hiện những việc không thực sự thuộc chuyên trách của mình, như kiểm tra giấy tờ thủ tục. Trong khi đó, nếu giấy tờ thủ tục đến chính xác, họ có thể bắt đầu công việc của mình ngay và tập trung cho việc đó.

Khi có kết quả từ bộ phận chuyên trách, bộ phận một cửa lại thay mặt trả kết quả cho người dân. Đồng thời bộ phận này có thể thực hiện thêm các yêu cầu phụ từ người dân liên quan đến kết quả chính.

Bộ phận một cửa hoạt động theo ý tưởng của mẫu thiết kế proxy: kiểm soát truy cập vào dịch vụ cụ thể; chỉ kích hoạt dịch vụ khi yêu cầu tới phù hợp; thực hiện thêm các dịch vụ phụ khi hoàn thành yêu cầu.

Giờ quay trở lại thế giới lập trình. Hãy tưởng tượng quá trình truy xuất cơ sở dữ liệu.

Bạn có thể cho phép client trực tiếp gọi các code truy xuất cơ sở dữ liệu.

Problem solved by Proxy pattern

Tuy nhiên, việc truy xuất cơ sở dữ liệu thường phức tạp, tốn thời gian và tài nguyên xử lý. Nếu client không đủ điều kiện truy xuất hoặc yêu cầu của client không phù hợp, việc cho client trực tiếp thực hiện code truy xuất dữ liệu gây ra sự lãng phí tài nguyên.

Khi này mô hình proxy trở nên rất phù hợp: một object gọn nhẹ (proxy) giờ chắn giữa client và code truy xuất dữ liệu. Proxy kiểm tra mọi điều kiện trước khi thay mặt client gọi tới code truy xuất dữ liệu.

Solution with the Proxy pattern

Sơ đồ UML của mẫu thiết kế Proxy

Dưới đây là sơ đồ UML của mẫu thiết kế Proxy.

sơ đồ uml của mẫu thiết kế proxy design pattern

Trong bản thiết kế trên có một số điểm lưu ý:

Subject là class thực sự giúp bạn xử lý yêu cầu. Tuy nhiên, client code sẽ không được trực tiếp làm việc với object của class này.

ISubject là một interface có cùng các mô tả phương thức như của Subject. Trong sơ đồ trên, cả Subject và ISubject đều có phương thức Request. Client sẽ chứa (has-a) biến kiểu ISubject (và biến này sẽ trỏ tới một object proxy).

Proxy là class thực thi giao diện ISubject. Một object của Proxy sẽ được client chứa và sử dụng thay cho object của Subject. Các phương thức của Subject được gọi thông qua object của Proxy. Nói cách khác, object của Proxy sẽ thay mặt client gọi tới phương thức thực sự của Subject.

Bạn có thể thấy, sơ đồ thiết kế của Proxy khá đơn giản. Điểm mấu chốt là Proxy phải có cùng mô tả phương thức như của Subject thực, đồng thời chắn giữa client và Subject. Client không gọi trực tiếp Subject mà gọi qua Proxy. Proxy thay mặt client gọi tới Subject. Qua quá trình này, Proxy kiểm soát việc truy xuất Subject.

Thực hiện mẫu thiết kế Proxy bằng C#

Khi bạn đã hiểu nguyên lý chung của Proxy, giờ hãy cùng viết một chương trình đơn giản thực thi cho mẫu thiết kế này.

Chương trình dưới đây lặp lại đúng bản thiết kế đã trình bày ở trên. Chương trình giả lập việc đăng ký tài khoản đơn giản từ giao diện dòng lệnh.

Để tiện lợi khi viết các chương trình nhỏ với giao diện dòng lệnh, trong các ví dụ sau sử dụng một bộ thư viện class tạo sẵn.

Bạn có thể tải file thư viện từ đường link sau:
https://1drv.ms/u/s!Ar_aj4rIJ2qGkZU4EYBdm4K3EptLTg?e=9ecAug
Sau khi tải về bạn tham chiếu chương trình tới file thư viện Framework.dll.

Bộ thư viện này hỗ trợ bạn nhanh chóng xây dựng ứng dụng console với khả năng tiếp nhận và xử lý lệnh/truy vấn từ người dùng + tham số của lệnh. Nó cũng có một số class hỗ trợ hiển thị dữ liệu trên console. Thêm vào đó, nếu ứng dụng phức tạp hơn, bạn có thể sử dụng một số class hỗ trợ để viết code theo mô hình MVC cho console.

Nếu quan tâm, bạn có thể đọc thêm loạt bài về cách xây dựng bộ thư viện hỗ trợ console này.

using System;
using Framework;

namespace P01_Concept
{
    class Subject : ISubject
    {
        public void Request(string name)
        {
            ViewHelper.WriteLine($"Hello, {name}. I'm the real subject. I'm doing my job for you", ConsoleColor.Cyan);
        }
    }

    interface ISubject
    {
        void Request(string name);
    }

    class Proxy : ISubject
    {
        private readonly Subject _subject;

        public Proxy() => _subject = new Subject();

        public Proxy(Subject subject) => _subject = subject;

        public void Request(string name)
        {
            // chạy trước dịch vụ chính
            ViewHelper.WriteLine($"Hello, {name}. I'm the proxy. Your request will be processing now. Thank you!", ConsoleColor.Yellow);
            // chạy dịch vụ chính
            _subject.Request(name);
            // chạy sau khi hoàn thành dịch vụ chính
            ViewHelper.WriteLine($"Greating! I'm the proxy again. Your work is done, {name}. Goodbye!", ConsoleColor.Green);
        }
    }

    class Program
    {
        static ISubject _proxy = new Proxy();

        static void Main(string[] args)
        {
            var app = new Application
            {
                Title = "PROXY DESIGN PATTERN",
                Config = RegisterRoutes
            };
            app.Run();
        }

        private static void RegisterRoutes()
        {
            var router = Router.Instance;
            router.Register(
                route: "register",
                action: (p) => { CreateAccount(p["name"]); },
                "Request to register a new account in the system.r\nSyntax: register ? name = ..."
                );
        }

        private static void CreateAccount(string name)
        {
            _proxy.Request(name);
        }
    }
}

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

kết quả chạy chương trình minh họa mẫu thiết kế proxy design pattern

Chương trình đơn giản trên thực hiện lại đúng thiết kế UML đã trình bày. Bạn để ý thấy rằng, client code (lớp Program) chứa object của Proxy. Nó cũng gọi tới phương thức Request của Proxy.

Tuy nhiên, Proxy bổ sung thêm lệnh riêng vào trước và sau quá trình thực thi thực sự của Subject. Trong các tình huống thực, đây chính là nơi viết code kiểm soát quá trình truy xuất object thực, cũng như thực hiện các thao tác bổ sung.

Kết luận

Trong bài học này chúng ta đã tìm hiểu mẫu thiết kế Proxy và cách thực hiện cơ bản của nó trên C#. Có một số tình huống có thể sử dụng Proxy:

  • Bạn cần kiểm soát truy xuất object;
  • Bạn chỉ muốn tạo object khi thực sự cần thiết;
  • Object tiêu tốn nhiều tài nguyên để khởi tạo và hoạt động;
  • Thực hiện các tác vụ bổ sung mỗi khi client truy xuất object.

Nếu có thắc mắc hoặc cần trao đổi thêm, mời bạn viết trong phần Thảo luận cuối trang.
Nếu cần trao đổi riêng với chúng tôi, hãy gửi email hoặc nhắn tin qua form liên hệ.
Nếu bài viết hữu ích với bạn, hãy giúp chúng tôi chia sẻ tới mọi người.
Đăng ký theo dõi trang facebook để nhận thông tin về bài viết mới.
Tắt Adblocker hoặc whitelist trang để hỗ trợ chúng tôi.
Cảm ơn bạn!

* Bản quyền bài viết thuộc về Tự học ICT. Đề nghị tôn trọng bản quyền. DMCA.com Protection Status
Subscribe
Notify of
guest
0 Thảo luận
Inline Feedbacks
View all comments