Nội dung
Mục tiêu
Adapter là một mẫu thiết kế cấu trúc cho phép các đối tượng có giao diện không tương thích có thể tương tác nhau.
Đặt vấn đề
Hãy tưởng tượng rằng bạn đang viết một ứng dụng theo dõi thị trường chứng khoán. Ứng dụng tải dữ liệu từ nhiều nguồn ở định dạng XML, sau đó hiển thị các biểu đồ và sơ đồ đẹp mắt cho người dùng.
Tại một thời điểm, bạn quyết định cải thiện ứng dụng bằng cách tích hợp thư viện phân tích thông minh của bên thứ 3. Nhưng có một điểm lưu ý, thư viện chỉ hoạt động với dữ liệu ở định dạng JSON.
Bạn có thể thay đổi thư viện để làm việc với XML. Tuy nhiên, điều này có thể phá vỡ một số mã hiện có của thư viện. Và tệ hơn, bạn có thể không có quyền truy cập vào mã nguồn của thư viện ngay từ đầu, khiến cho phương pháp này không thể thực hiện được.
Giải pháp
Bạn có thể tạo một adapter. Đây là một đối tượng đặc biệt chuyển đổi giao diện của một đối tượng để đối tượng khác có thể hiểu được nó.
Adapter bao bọc một trong các đối tượng để che giấu sự phức tạp của quá trình chuyển đổi diễn ra bên trong. Đối tượng được bọc thậm chí không biết về adapter. Ví dụ, bạn có thể bao một đối tượng mà hoạt động theo mét và ki lô mét với một adapter chuyển đổi tất cả các dữ liệu thành các đơn vị feet và mile.
Adapter không chỉ có thể chuyển đổi dữ liệu thành nhiều định dạng khác nhau mà còn có thể giúp các đối tượng có giao diện khác nhau tương tác được. Dưới đây là cách nó hoạt động:
- Adapter có một giao diện, tương thích với một trong các đối tượng hiện có.
- Sử dụng giao diện này, đối tượng hiện có có thể gọi các phương thức của adapter một cách an toàn.
- Khi nhận được lời gọi, adapter sẽ chuyển yêu cầu tới đối tượng thứ hai, nhưng theo định dạng và thứ tự mà đối tượng thứ hai mong đợi.
Đôi khi, thậm chí có thể tạo adapter hai chiều có thể chuyển đổi lời gọi theo cả hai hướng.
Quay lại ứng dụng thị trường chứng khoán của chúng ta. Để giải quyết vấn đề về các định dạng không tương thích, bạn có thể tạo adapter XML sang JSON cho mọi lớp của thư viện phân tích mà chương trình làm việc trực tiếp. Sau đó, điều chỉnh mã để chỉ giao tiếp với thư viện thông qua các adapter này. Khi một adapter nhận được lời gọi, nó sẽ dịch dữ liệu XML đến thành một cấu trúc JSON và chuyển cuộc gọi đến các phương thức thích hợp của một đối tượng phân tích được bao bọc.
Cấu trúc
Object adapter
Việc triển khai này sử dụng nguyên tắc hợp thành đối tượng: adapter thực hiện giao diện của một đối tượng và bao bọc đối tượng khác. Nó có thể được thực hiện trong tất cả các ngôn ngữ lập trình phổ biến.
- Client là một lớp chứa logic nghiệp vụ hiện có của chương trình.
- Giao diện Client mô tả một giao thức mà các lớp khác phải tuân theo để có thể cộng tác với client.
- Service là một số lớp hữu ích (thường là bên thứ 3). Client không thể sử dụng trực tiếp lớp này vì nó có giao diện không tương thích.
- Adapter là một lớp có thể hoạt động với cả Client và Service, nó triển khai giao diện Client, trong khi bao đối tượng Service. Adapter nhận các lời gọi từ Client thông qua giao diện adapter và chuyển chúng thành các lời gọi đến đối tượng service được bao bọc theo định dạng mà nó có thể hiểu được.
- Client không được ghép nối với lớp Adapter cụ thể mà nó hoạt động thông qua giao diện Client. Nhờ đó, bạn có thể tạo các kiểu adapter mới cho chương trình mà không phá vỡ client hiện có. Điều này có thể hữu ích khi giao diện của lớp service được thay đổi hoặc thay thế: bạn có thể chỉ cần tạo một lớp adapter mới mà không cần thay đổi client.
Class adapter
Việc triển khai này sử dụng tính kế thừa: adapter kế thừa các giao diện từ cả hai đối tượng cùng một lúc. Lưu ý rằng cách tiếp cận này chỉ có thể được thực hiện trong các ngôn ngữ lập trình hỗ trợ đa kế thừa, chẳng hạn như C++.
Adapter không cần phải bọc bất kỳ đối tượng nào vì nó kế thừa các hành vi từ client và service. Việc điều chỉnh xảy ra trong các phương thức bị ghi đè. Kết quả có thể được sử dụng thay cho một lớp client hiện có.
Khả năng áp dụng
- Sử dụng Adapter khi bạn muốn sử dụng một số lớp hiện có, nhưng giao diện của nó không tương thích với phần còn lại của mã của bạn.
- Sử dụng Adapter khi bạn muốn sử dụng lại một số lớp con hiện có thiếu một số chức năng phổ biến mà không thể thêm vào lớp cha.
Ưu và nhược điểm
😄😄😄
Nguyên tắc Đơn trách nhiệm. Bạn có thể tách giao diện hoặc mã chuyển đổi dữ liệu khỏi logic nghiệp vụ chính của chương trình.
Nguyên tắc Mở / Đóng. Bạn có thể tạo các kiểu adapter mới trong chương trình mà không vi phạm mã client hiện có, miễn là chúng hoạt động với adapter thông qua giao diện client.
🙁🙁🙁
Độ phức tạp tổng thể của chương trình tăng lên vì bạn cần tạo một tập hợp các giao diện và lớp mới. Đôi khi, đơn giản hơn chỉ là thay đổi lớp service để nó khớp với phần còn lại của chương trình.
Mối quan hệ với các mẫu khác
Bridge thường được thiết kế up-front, cho phép bạn phát triển các phần của ứng dụng một cách độc lập với nhau. Ngược lại, Adapter thường được sử dụng với một ứng dụng hiện có để làm cho một số lớp không tương thích hoạt động với nhau.
Adapter thay đổi giao diện của một đối tượng hiện có, trong khi Decorator tăng cường chức năng một đối tượng mà không thay đổi giao diện của nó. Ngoài ra, Decorator hỗ trợ đệ quy, điều này không thể thực hiện được khi bạn sử dụng Adapter.
Adapter cung cấp một giao diện khác cho đối tượng được bao bọc, Proxy cung cấp cho nó một giao diện tương tự và Decorator cung cấp cho nó một giao diện tăng cường.
Facade định nghĩa một giao diện mới cho các đối tượng hiện có, trong khi Adapter cố gắng làm cho giao diện hiện có có thể sử dụng được. Adapter thường chỉ bao bọc một đối tượng, trong khi Facade hoạt động với toàn bộ hệ thống con của các đối tượng.
Bridge, State, Strategy (và ở một mức độ nào đó là Adapter) có cấu trúc rất giống nhau. Thật vậy, tất cả các mẫu này đều dựa trên hợp thành, tức là ủy thác công việc cho các đối tượng khác. Tuy nhiên, chúng đều giải quyết các vấn đề khác nhau. Mẫu thiết kế không chỉ là một công thức để cấu trúc chương trình của bạn theo một cách cụ thể. Nó cũng có thể giao tiếp với các nhà phát triển khác về vấn đề mà mẫu giải quyết.
Để lại một bình luận