Proxy Design Pattern – Trợ thủ đắc lực của Developers

1. Reviews

  • Proxy (hay còn gọi là Surrogate) là một mẫu thiết kế thuộc nhóm cấu trúc (Structural Pattern).
  • Điều khiển và tinh chỉnh gián tiếp việc truy xuất đối tượng người dùng trải qua một đối tượng người dùng được ủy nhiệm
  • Cung ứng 1 class thay mặt để quản lí sự truy xuất đến thành phần của một class khác
  • Xử lý vấn đề security, perfomance, validation,…
  • Tần suất tận dụng: tương đối cao

2. Mục tiêu Thành lập và hoạt động

Problem

Giả sử ta có một bài toán truy vấn vào 1 object lớn. Object này chiếm nhiều tài nguyên khối hệ thống. Ta cần nó thường xuyên, nhưng không phải luôn luôn luôn luôn. Ví dụ như khi ta truy vấn cơ sở tài liệu.

Ta rất có thể implement lazy initialization, tức là chỉ tạo khi cần. Lúc này client muốn truy vấn đều phải chạy qua đoạn code này, tuy nhiên vấn đề phát sinh là sẽ làm code duplicate

Điều hay nhất là rất có thể là đưa dòng code này vào chính đối tượng người dùng đó. Nhưng nếu lớp này là 3rd party thì không thể.

Một vấn đề khác về mặt security, hoặc ta muốn validate nó mà không cần đến client, như khi upload 1 file nào đó.

Solution

Proxy nói rằng ta cần tạo 1 lớp mới thay mặt cho lớp service đang xuất hiện với cùng 1 interface, lớp này gọi là proxy. Tiếp theo khi update ứng dụng thì nó sẽ truyền đối tượng người dùng proxy cho toàn bộ client phía đối tượng người dùng gốc. Khi nhận 1 yêu cầu từ phía client, proxy tạo 1 service thật và delegate toàn bộ nhiệm vụ đến nó.

Nếu phải chạy thứ gì đó trước hay sau logic chính của lớp, proxy được cho phép làm điều này mà không làm thay đổi lớp đó. Cũng chính vì Proxy implement cùng interface với lớp chính, nó rất có thể kết nối với bất kể client nào đang chờ liên lạc từ server thật.

Vấn đáp hai câu này để quyết định cài proxy hay là không:

  • Có một “expensive resource” nhưng chỉ khởi tạo khi cần đến nó?
  • Có một resource cần kiểm tra security, availability hay validation mà không muốn làm ở phía Client?

=> Wrap 1 object và hỗ trợ những phương thức để truy vấn vào object đó

Proxy giải quyết và xử lý những vấn đề:

  • Có những trường hợp mà quý khách hàng không hoặc không thể tham chiếu trực tiếp đến một Đối tượng người tiêu dùng, nhưng vẫn muốn tương tác với đối tượng người dùng.
  • Đối tượng người tiêu dùng proxy rất có thể hoạt động và sinh hoạt như trung gian giữa máy khách và đối tượng người dùng đích.
  • Đối tượng người tiêu dùng proxy có cùng giao diện với đối tượng người dùng đích.
  • Proxy giữ một tham chiếu đến đối tượng người dùng tiềm năng và rất có thể chuyển tiếp những yêu cầu đến tiềm năng theo yêu cầu
  • Proxy hữu ích ở bất kể nơi nào mong muốn tham chiếu phức tạp hơn đến một đối tượng người dùng hơn là con trỏ giản dị và đơn giản hoặc tham chiếu giản dị và đơn giản rất có thể cungười cấp

3. Kiến trúc

Những thành phần trong quy mô:

  • ServiceInterface: Khái niệm giao diện chung cho Service và Proxy để Proxy rất có thể được tận dụng ngẫu nhiên nơi nào mà Service được mong đợi.
  • Service: Khái niệm ServiceInterface mà Proxy thay mặt.
  • Proxy:
    • Duy trì một tham chiếu được cho phép Proxy truy vấn vào Service . Proxy rất có thể tham chiếu đến ServiceInterface nếu Service và ServiceInterface giống nhau.
    • Cung ứng interfaces giống với ServiceInterface để Proxy rất có thể thay thế cho Service .
    • Kiểm soát quyền truy vấn vào Service và chịu trách nhiệm cho việc tạo và xóa nó.
    • Một vài trách nhiệm khác tùy theo loại Proxy:
    • Remote proxies chịu trách nhiệm mã hóa một yêu cầu và những đối số của nó và gửi yêu cầu được mã hóa đến Service trong một không khí địa chỉ khác.
    • Virtual proxies rất có thể cache thông tin bổ xung về Service để trì hoãn việc truy vấn nó.
    • Protection proxies kiểm tra xem có quyền truy vấn quan trọng để triển khai yêu cầu hay là không.

4. Ưu & nhược điểm

Ưu điểm

  • Open/Closed Principle: Bạn cũng có thể thêm proxy mới mà không cần thay đổi service hoặc clients.
  • Nâng cao Performance trải qua lazy loading.
  • Nó hỗ trợ sự bảo vệ cho đối tượng người dùng từ thực trái đất bên phía ngoài.
  • Giảm ngân sách khi có nhiều truy vấn vào đối tượng người dùng có ngân sách khởi tạo lúc đầu lớn.

Nhược điểm

  • Mã rất có thể trở thành phức tạp hơn vì bạn phải thêm lớp mới.
  • Phản hồi từ service rất có thể bị trì hoãn.

5. Khi nào thì tận dụng

Tiếp sau đây mọi người rất có thể liệt kê một số trong những trường hợp mà khi gặp sẽ phải lưu ý đến tận dụng Proxy pattern:

  • Lazy initialization (virtual proxy): Khi người có một đối tượng người dùng dịch vụ nặng gây lãng phí tài nguyên khối hệ thống do luôn luôn hoạt động và sinh hoạt, tuy vậy thỉnh thoảng người chỉ việc nó.
  • Access control (protection proxy): Khi mình thích chỉ những quý khách hàng rõ ràng mới rất có thể tận dụng đối tượng người dùng dịch vụ.
  • Local execution of a remote service (remote proxy): Đó là khi đối tượng người dùng service được đặt trên một sever từ xa.
  • Logging requests (logging proxy): Khi mình thích giữ lịch sử dân tộc của những yêu cầu so với đối tượng người dùng service.
  • Caching request results (caching proxy): Khi người cần lưu trữ thành quả của những yêu cầu máy khách và quản lý và vận hành vòng đời của cục nhớ cache này, quan trọng nếu thành quả khá lớn.
  • Smart reference: Khi người cần loại bỏ một đối tượng người dùng nặng khi không hề có máy khách nào tận dụng nó.

6. Source code minh họa với C#

  • B1: Nếu không hề có service interface, tạo 1 cái để proxy và service rất có thể thay thế nhau
  • B2: Tạo 1 lớp proxy. Nó nên có một trường lưu tham chiếu đến service. Thường proxy tạo và quản lí life cycle của service. Thỉnh thoảng service được truyền đến proxy thông qua một constructor từ client.
  • B3: Implement proxy => rất có thể delegate công việc tới service
  • B4: Suy xét tạo 1 phương thức static để quyết định xem client gọi proxy hay service.
  • B5: Thiết đặt thêm lazy initialization (nếu muốn)

public interface Video { void display(); } public class RealVideo : Video { private string _fileName; public RealVideo(string fileName) { _fileName = fileName; loadFromDisk(_fileName); } public void display() { Console.WriteLine(“Displaying ” + _fileName); } private void loadFromDisk(string fileName) { Console.WriteLine(“Loading ” + fileName); } } public class ProxyVideo : Video { private RealVideo realVideo; private string fileName; public ProxyVideo(string fileName) { this.fileName = fileName; } public void display() { if (realVideo == null) // lazy loading { realVideo = new RealVideo(fileName); } realVideo.display(); } } class Client { static void Main(string[] args) { Video image = new ProxyVideo(“Design Pattern.mp4”); //video sẽ tiến hành load từ ổ đĩa image.display(); Console.WriteLine(“After loading first timen”); //video sẽ k tải lại từ ổ đĩa nữa image.display(); } }

7. Design Pattern liên quan

  • Adapter: Adapter hỗ trợ một Interface khác với Interface của object mà chúng adapt, Proxy thì trái lại, hỗ trợ cùng một Interface cho subject của nó. Proxy được tận dụng để bảo vệ truy vấn và sẽ từ chối trổ tài hành vi mà subject triển khai.
  • Decorator: Decorator có cách triển khai khá giống với Proxy (dựa trên Composition) nhưng chúng có mục tiêu tận dụng không giống nhau, Decorator thêm trách nhiệm cho đối tượng người dùng trong lúc Proxy kiểm soát truy vấn vào đối tượng người dùng đó.

Nội dung bài viết của tớ đến đấy là kết thúc, cảm ơn những người đã theo dõi. Nếu những người thấy có ích rất có thể tò mò thêm Series Design Patterns – Trợ thủ đắc lực của Developers của tớ!!

Tài liệu tìm hiểu thêm

[1] Refactoring.Guru. https://refactoring.guru/design-patterns

[2] Design Patterns for Dummies, Steve Holzner, PhD

[3] Head First, Eric Freeman

[4] Gang of Four Design Patterns 4.0

[5] Dive into Design Pattern

You May Also Like

About the Author: v1000