Mẫu bộ chuyển đổi
Thuộc phần Lập trình hướng đối tượng trong hành trình PHP của Coddy. Bài học 76 trên 91.
Adapter Pattern 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 hoạt động cùng nhau. Mẫu này đóng vai trò cầu nối giữa hai giao diện, chuyển đổi lời gọi từ định dạng này sang định dạng khác.
Hãy tưởng tượng bạn đang xây dựng một ứng dụng xử lý thanh toán và cần tích hợp một thư viện thanh toán của bên thứ ba. Thư viện hoạt động hoàn hảo, nhưng giao diện của nó không khớp với những gì code của bạn cần. Thay vì viết lại toàn bộ ứng dụng, bạn tạo một bộ chuyển đổi để chuyển đổi giữa hai giao diện.
<?php
// Giao diện mà ứng dụng của bạn yêu cầu
interface PaymentProcessor {
public function pay(float $amount): string;
}
// Thư viện bên thứ ba có giao diện khác
class StripeAPI {
public function createCharge(int $cents, string $currency): string {
return "Charged {$cents} {$currency} via Stripe";
}
}
Bộ điều hợp triển khai giao diện mà bạn mong đợi, đồng thời sử dụng lớp bên thứ ba ở bên trong:
<?php
class StripeAdapter implements PaymentProcessor {
public function __construct(private StripeAPI $stripe) {}
public function pay(float $amount): string {
$cents = (int)($amount * 100);
return $this->stripe->createCharge($cents, 'USD');
}
}
$stripe = new StripeAPI();
$processor = new StripeAdapter($stripe);
echo $processor->pay(29.99);
Đầu ra:
Charged 2999 USD via StripeBộ chuyển đổi đổi đô la sang xu và gọi phương thức phù hợp. Code ứng dụng của bạn chỉ biết đến PaymentProcessor, hoàn toàn không cần quan tâm đến các yêu cầu riêng của Stripe. Nếu sau này bạn chuyển sang nhà cung cấp dịch vụ thanh toán khác, bạn chỉ cần tạo một bộ chuyển đổi mới mà không phải thay đổi code hiện có.
Thử thách
DễHãy xây dựng một hệ thống chuyển đổi nhiệt độ bằng Mẫu bộ chuyển đổi (Adapter Pattern). Bạn có một cảm biến nhiệt độ cũ, cho kết quả đo theo độ Fahrenheit, nhưng ứng dụng thời tiết hiện đại của bạn cần nhiệt độ theo độ Celsius. Thay vì sửa đổi một trong hai hệ thống, bạn sẽ tạo một bộ chuyển đổi để kết nối chúng.
Bạn sẽ sắp xếp code trong bốn tệp:
TemperatureSensor.php: Định nghĩa một giao diện (interface)TemperatureSensormà ứng dụng thời tiết cần dùng. Giao diện này cần có phương thứcgetTemperature(): floatđể trả về nhiệt độ theo độ Celsius.LegacySensor.php: Tạo lớp (class)LegacySensormô phỏng phần cứng cũ. Lớp này có giao diện khác với giao diện ứng dụng cần:- Lớp nhận số đo theo độ Fahrenheit trong hàm khởi tạo (constructor). Hãy dùng cú pháp khai báo thuộc tính trong hàm khởi tạo.
- Lớp có phương thức
readFahrenheit(): floatđể trả về giá trị Fahrenheit đã lưu.
LegacySensorAdapter.php: Thêm cả giao diện TemperatureSensor và lớp LegacySensor vào tệp này. Tạo lớpLegacySensorAdaptertriển khaiTemperatureSensorvà bao bọc mộtLegacySensor. Bộ chuyển đổi cần:- Nhận một
LegacySensortrong hàm khởi tạo - Triển khai
getTemperature()bằng cách đọc giá trị Fahrenheit từ cảm biến cũ rồi đổi sang Celsius theo công thức:(fahrenheit - 32) * 5 / 9
- Nhận một
main.php: Thêm tệp LegacySensorAdapter. Bạn sẽ nhận một đầu vào: nhiệt độ theo độ Fahrenheit.Tạo một
LegacySensorvới nhiệt độ đầu vào, rồi bao bọc nó trong mộtLegacySensorAdapter. GọigetTemperature()trên bộ chuyển đổi và in ra kết quả đã làm tròn đến hai chữ số thập phân.Định dạng đầu ra cần là:
Temperature: [celsius]C
Thử thách này minh họa cách Mẫu bộ chuyển đổi giúp bạn tích hợp các giao diện không tương thích mà không cần sửa đổi code hiện có. Ứng dụng thời tiết chỉ làm việc với giao diện TemperatureSensor và hoàn toàn không biết rằng các số đo thực tế đến từ cảm biến Fahrenheit cũ.
Tự làm thử
<?php
require_once 'LegacySensorAdapter.php';
// Đọc đầu vào
$fahrenheit = floatval(trim(fgets(STDIN)));
// TODO: Tạo một LegacySensor với nhiệt độ đầu vào
// TODO: Bọc đối tượng đó bằng LegacySensorAdapter
// TODO: Gọi getTemperature() trên adapter
// TODO: In ra kết quả làm tròn đến hai chữ số thập phân
// Định dạng đầu ra: Temperature: [celsius]C
?>Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Lập trình hướng đối tượng
1Nền tảng về OOP
Tệp bên ngoàiGiới thiệu về OOPLớp và đối tượngTừ khóa $thisPhương thứcThuộc tínhHàm khởi tạo (__construct)Hàm hủy (__destruct)Ôn tập: máy tính đơn giản4Kế thừa
Kế thừa cơ bảnTừ khóa parent::Ghi đè phương thứcTừ khóa finalLớp trừu tượngÔn tập: hệ thống phân cấp nhân viên7Đóng gói
Công khai, được bảo vệ, riêng tưTìm hiểu sâu về bộ điều chỉnh quyền truy cậpGetter và setterẨn thông tinRút gọn hàm khởi tạo (8.0)Ôn tập: hệ thống hồ sơ học sinh10Các khái niệm OOP nâng cao
Kết hợp hay kế thừaTiêm phụ thuộcLớp ẩn danhKiểu liệt kê (PHP 8.1)Fiber (PHP 8.1)Tìm hiểu sâu về sao chép đối tượngBộ sinh và bộ lặp13Mẫu thiết kế phần 2
Mẫu lệnhMẫu bộ chuyển đổiMẫu trang tríMẫu phương thức khuôn mẫuMẫu trạng tháiMẫu tổ hợpMẫu Repository2Không gian tên và tự động nạp
Giới thiệu về không gian tênTừ khóa useChuẩn tự động nạp PSR-4Trình tự động nạp của ComposerÔn tập: dự án có tổ chức5Giao diện và hợp đồng
Giới thiệu về giao diệnTriển khai giao diệnTriển khai nhiều giao diệnGiao diện và lớp trừu tượngGợi ý kiểu với giao diệnÔn tập: Máy tính hình học8Phương thức ma thuật
Giới thiệu về phương thức ma thuật__toString và __debugInfo__get, __set, __isset, __unset__call và __callStatic__clone và sao chép đối tượng__serialize và __unserializeÔn tập: Bộ sưu tập tùy chỉnh3Thuộc tính của lớp
Thuộc tính instance và staticHằng số trong lớpPhương thức và thuộc tính staticThuộc tính private và protectedThuộc tính chỉ đọc (PHP 8.1)Ôn tập: Trình quản lý tài khoản ngân hàng6Đa hình
Xem lại việc ghi đè phương thứcĐa hình qua giao diệnGợi ý kiểu và kiểu hợpLiên kết tĩnh muộnÔn tập: bộ xử lý thanh toánTự luyện tập: Trình biên dịch PHP online