+1

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 class BankAccount đơn giản để theo dõi các hoạt động của bank account

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

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.png

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.

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

Bài viết liên quan:


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí