Khi bạn đang mơ thì người khác đang nỗ lực.

Adapter Pattern cắm là chơi

1. Adapter Pattern là gì?

Adapter Pattern là một trong số những Design Pattern được giới thiệu bởi Gang of Four, nó nằm trong nhóm Structural Design Pattern, các mẫu liên quan đến cấu trúc và kết cấu các đối tượng trong lập trình hướng đối tượng. Đây là một trong những mẫu có tần suất sử dụng khá nhiều trong lập trình.

In software engineering, the adapter pattern is a software design pattern that allows the interface of an existing class to be used for another interface. It is often used to make existing classes work with others without modifying their source code.

Trong phát triển ứng dụng, áp dụng adapter pattern cho phép một interface của một lớp đang sử dụng có thể được dùng bởi một interface khác. Việc thay thế một lớp đang dùng với một lớp khác không cần thay đổi mã nguồn các lớp.

Adapter Pattern giống như tên gọi của nó là những "bộ chuyển đổi" giúp các thành phần mới có thể cắm vào hệ thống không hỗ trợ cổng của nó. Trong thực tế, bộ chuyển đổi (adapter) được sử dụng rất nhiều, ví dụ: bạn vẫn hay xem phim trên màn hình lớn TV bằng cách cắm dây HDMI từ máy laptop sang TV, một thời gian sau bạn chuyển từ chiếc laptop Dell cũ kỹ sang con MacBook Pro cực đẹp, nhưng tiếc thay nó không có cổng HDMI để cắm dây HDMI lên TV. Rất may là các chuyên gia trong lĩnh vực điện tử đã biết có vấn đề này và họ thiết kế bộ chuyển đổi từ DisplayPort sang HDMI, và bạn đã có thể truyền hình ảnh từ con MacBook lên TV để thưởng thức những bộ phim bom tấn.

Adapter

Một ví dụ khác là chuẩn ổ cắm, ở Việt Nam thường sử dụng ổ cắm điện có hai chân, trong khi một số thiết bị điện như laptop, điện thoại, tivi... lại có phích cắm 3 chân, đặc biệt là hàng nhập do tiêu chuẩn châu Âu, Mỹ là ba chân, như vậy chúng ta cần một bộ chuyển từ ba chân sang hai chân để có thể hoạt động được.

2. Adapter Pattern UML

Adapter Pattern UML Trong đó:

  • Client: là một class hoặc một đối tượng sử dụng Adaptee public API.
  • Adapter: Cung cấp một interface chung giữa Adaptee và Client
  • Adaptee: là module/class mới cần thay thế cho module/class cũ.

3. Ví dụ về Adapter Pattern

Một tình huống đã từng gặp khi tôi còn đang làm corebank trong ngân hàng, sau một thời gian chúng tôi đã tích hợp được thư viện thanh toán SmartLink với hệ thống core, tuy nhiên chỉ sau đó vài năm khi ngân hàng nhà nước bắt buộc phải tích hợp với Banknet, công toi ư. Mặc dù cả hai bộ thư viện từ hai mạng thanh toán đều thực hiện những công việc tương tự nhưng về chi tiết là khác nhau. Thật may mắn vì Adapter Pattern đã giải quyết vấn đề này, nó sử dụng một adapter class để "phiên dịch" một interface của class mới thành interface của một class đang sử dụng. Adapter pattern được sử dụng khi hai hoặc nhiều class làm cùng những việc tương tự nhưng tên các phương thức là khác nhau.

class SmartLinkTransfer {
  function addItem($itemName) {
    echo "1 item added: " . $itemName;
  }

  function addFund($itemAmount) {
    echo "1 item added with amount: " . $itemAmount);
  }
}

Khi đó sử dụng class này trong các hệ thống tích hợp với corebank:

class Customer {
  private $pay;

  function __construct($pay) {
    $this -> pay = $pay;
  }

  function transfer($itemName, $itemAmount) {
    $this->pay->addItem($itemName);
    $this->pay->addFund($itemAmount);
  }
}

Sử dụng các class này chúng ta có thể thực hiện các chuyển khoản:

$pay = new SmartLinkTransfer();
$customer = new Customer($pay);
$customer->tranfer("Chuyển tiền thuê hosting", 2000000);

Một ngày đẹp trời, ngân hàng nhà nước yêu cầu các tổ chức tài chính chuyển sang kết nối với Banknet với thư viện như sau:

class BanknetTransfer {
  public function addOneItem($name) {
    echo "1 item added: " . $name;
  }

  public function addItemAmount($amount) {
    echo "1 item added with amount: " . $price;
  }

  // Một phương thức khác không tương đồng với SmartLink
  public function addItemAndAmount($name ,$amout) {
    $this->addOneItem($name);
    $this->addItemAmount($amout);
  }
}

Nếu sử dụng đoạn code ở trên cho chuyển khoản:

$pay = new BanknetTransfer();
$customer = new Customer($pay);
$customer->tranfer("Chuyển tiền thuê hosting", 2000000);

Chúng ta gặp phải lỗi gọi một phương thức không xác định BanknetTransfer::addItem, trong khi các class SmartLinkTransfer và BanknetTransfer có sự tương đồng. Chúng ta áp dụng Adapter Pattern để xử lý.

Bước 1: Extract một interface từ class gốc SmartLinkTransfer:

interface SmartLink {
  function addItem($itemName);
  function addFund($itemAmount);
}

Lớp gốc SmartLinkTransfer sẽ implement interface này:

class SmartLinkTransfer implement SmartLink {
  function addItem($itemName) {
    echo "1 item added: " . $itemName;
  }

  function addFund($itemAmount) {
    echo "1 item added with amount: " . $itemAmount);
  }
}

Bước 2: Viết adapter class BanknetToSmartLinkAdapter để chuyển đổi giao diện từ Banknet sang SmartLink.

class BanknetToSmartLinkAdapter implements SmartLink {         
  // Thuộc tính này tham chiếu đến class BanknetTransfer
  private $payObj;

  // Thiết lập tham chiếu thông qua phương thức khởi tạo
  function __construct($payObj) {
    $this -> payObj = $payObj; 
  }

  // Thêm phương thức với tên là tên phương thức bên class cũ và gọi đến 
  // phương thức tương ứng bên class mới
  function addItem($itemName) {
    $this->payObj->addOneItem($itemName);
  }
}

Như vậy, chúng ta có thể sử dụng Adapter này để gọi các phương thức của class mới BanknetTransfer mà không cần thay đổi gì phía bên trong:

$BanknetTransfer= new BanknetTransfer();
$pay = new BanknetToSmartLinkAdapter($BanknetTransfer);
$customer = new Customer($pay);
$customer->tranfer("Chuyển tiền thuê hosting", 2000000);

4. Lời kết

Các Design Pattern đều là những đúc kết kinh nghiệm trong các dự án lập trình, nó cũng xuất phát từ những ý tưởng hết sức thực tế. Môi trường lập trình hướng đối tượng cũng đang mô phỏng đúng những gì mà các đối tượng tương tác trong cuộc sống. Adapter Pattern là một trong những mẫu lập trình thú vị vì nó khá quen thuộc với chúng ta, việc kết nối các hệ thống với nhau là điều hết sức bình thường và nó cũng luôn thay đổi. Nhưng không vấn đề gì, Adapter Pattern đã giải quyết một cách triệt để vấn đề này.

FirebirD

Đam mê Toán học, Lập trình. Sở thích chia sẻ kiến thức, Phim hài, Bóng đá, Cà phê sáng với bạn bè.

Design Pattern sự tiến hóa trong lập trình

Laravel đơn giản, đẹp và hiệu quả hơn với Laravel Facade

1 Bình luận trong "Adapter Pattern cắm là chơi"

  1. DươngNN

    6 days ago

    Phản hồi

    Dùng từ hơi nhạy cảm "Cắm là chơi", tưởng có gì hay ho :)

Thêm bình luận