Design Pattern – Proxy
Proxy là gì? Proxy dịch ra thì nó có nghĩa là “ủy quyền” hay “đại diện” . Mục đích xây dựng Proxy pattern cũng chính vì muốn tạo ra một đối tượng sẽ ủy quyền, thay thế cho một đối tượng khác. Chúng ta xem ví dụ đơn giản sau: Ta xây dựng một ...
Proxy là gì?
Proxy dịch ra thì nó có nghĩa là “ủy quyền” hay “đại diện”. Mục đích xây dựng Proxy pattern cũng chính vì muốn tạo ra một đối tượng sẽ ủy quyền, thay thế cho một đối tượng khác.
Chúng ta xem ví dụ đơn giản sau:
Ta xây dựng một class BankAccount đơn giản để theo dõi các hoạt động của bank account
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
class BankAccount attr_reader :balance def initialize(starting_balance=0) @balance = starting_balance end def deposit(amount) @balance += amount end def withdraw(amount) @balance -= amount end end |
Đồng thời, ta xây dựng 1 class proxy cho BankAccount
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
class BankAccountProxy def initialize(real_object) @real_object = real_object end def balance @real_object.balance end def deposit(amount) @real_object.deposit(amount) end def withdraw(amount) @real_object.withdraw(amount) end end |
Ta thấy rằng class BankAccountProxy có các phương thức thực hiện giống hệt như BankAccount, thậm chí nó còn sử dụng chính đối tượng của BankAccount.
Như vậy về bản chất BankAccountProxy hoàn toàn có thể thay thế BankAccount với các thao tác và vai trò tương đương nhưng nó lại không phải BankAccount. Có thể nói BankAccountProxy đóng vai trò là ủy quyền của BankAccount.
Vì sao phải dùng Proxy?
Một câu hỏi đặt ra là vì sao chúng ta không khởi tạo và gọi trực tiếp class BankAccount mà phải thông qua Proxy.
Thực ra không phải bất cứ class hay object nào cũng cần phải có Proxy, chỉ có những class hoặc object đặc biệt mà chúng ta phải ủy quyền khi:
- Muốn bảo vệ quyền truy xuất vào các phương thức của object.
- Muốn bổ sung trước khi thực hiện phương thức của object.
- Muốn tạo object với chức năng được nâng cao hơn theo yêu cầu.
Làm thế nào để xây dựng 1 Proxy pattern
Proxy pattern về cơ bản sẽ gồm 3 thành phần chính:
- 1 class interface giao tiếp với client
- 1 class service sẽ thực hiện các thao tác thực sự
- 1 class proxy sẽ thực hiện các bước kiểm tra và gọi tới đối tượng của class service thật để thực hiện các thao tác sau khi kiểm tra.
Proxy bảo vệ các phương thức như thế nào
Cách đơn giản nhất là chúng ta thêm vào một method kiểm tra mỗi khi gọi tới các method ủy quyền.
Ví dụ như khi truy xuất các phương thức của BankAccount, chúng ta phải kiểm tra xem user đã đăng nhập chưa.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
require 'etc' class AccountProtectionProxy def initialize(real_account, owner_name) @subject = real_account @owner_name = owner_name end def deposit(amount) check_access return @subject.deposit(amount) end def withdraw(amount) check_access return @subject.withdraw(amount) end def balance check_access return @subject.balance end def check_access if Etc.getlogin != @owner_name raise "Illegal access: #{Etc.getlogin} cannot access account." end end end |
Rõ ràng, chúng ta có thể đưa các mã kiểm tra vào chính class BankAccount nhưng việc đưa mã kiểm tra vào Proxy giúp ta có cái nhìn tập trung hơn.
Proxy chỉ quan tâm xem ai được phép thực thi mà không cần hiểu thực thi như thế nào. Điều này giúp ta dễ dàng kiểm soát được vấn đề an ninh và bảo mật hoặc có thể dễ dàng thay đổi các phương thức trong BankAccount mà không còn lo ngại về vấn đề bảo mật nữa, giúp ta đóng gói được các thông tin cần được bảo vệ.
Tham khảo
Github (updating):https://github.com/ducnhat1989/design-patterns-in-ruby
Sách: “DESIGN PATTERNS IN RUBY” của tác giả Russ Olsen
:
- CÁC NGUYÊN TẮC TRONG DESIGN PATTERN
Techtalk via Viblo