Đa hình qua giao diện
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 34 trên 91.
Trong bài học trước, bạn đã tìm hiểu về tính đa hình thông qua kế thừa, trong đó các lớp con ghi đè phương thức của lớp cha. Giao diện là một cách mạnh mẽ khác để đạt được tính đa hình, đặc biệt khi làm việc với các lớp không liên quan nhưng có chung hành vi.
Với giao diện, tính đa hình xuất phát từ chính hợp đồng. Mọi lớp triển khai một giao diện đều đảm bảo có một số phương thức nhất định, bất kể hệ thống phân cấp kế thừa của lớp đó:
<?php
interface Notifiable {
public function send(string $message);
}
class EmailNotifier implements Notifiable {
public function send(string $message) {
return "Email: " . $message;
}
}
class SMSNotifier implements Notifiable {
public function send(string $message) {
return "SMS: " . $message;
}
}
class PushNotifier implements Notifiable {
public function send(string $message) {
return "Push: " . $message;
}
}
function notify(Notifiable $notifier, string $message) {
return $notifier->send($message);
}
echo notify(new EmailNotifier(), "Hello") . "\n";
echo notify(new SMSNotifier(), "Hello") . "\n";
echo notify(new PushNotifier(), "Hello");
Đầu ra:
Email: Hello
SMS: Hello
Push: HelloHàm notify() hoạt động với mọi đối tượng Notifiable. Các lớp này không có chung lớp cha nào, chúng hoàn toàn không liên quan đến nhau, ngoại trừ việc cùng triển khai một giao diện. Đây là ưu điểm chính so với tính đa hình dựa trên kế thừa: bạn có thể nhóm các lớp không liên quan với nhau dựa trên khả năng của chúng thay vì nguồn gốc kế thừa.
Điểm chính: Tính đa hình dựa trên giao diện cho phép dùng các lớp không liên quan thay thế cho nhau dựa trên hành vi chung, giúp code linh hoạt hơn và ít phụ thuộc vào các cách triển khai cụ thể.
Thử thách
DễHãy xây dựng một hệ thống lưu trữ minh họa tính đa hình dựa trên giao diện. Bạn sẽ tạo các hệ thống lưu trữ khác nhau, gồm hệ thống tệp và cơ sở dữ liệu, không có điểm chung nào ngoài việc cả hai đều triển khai cùng một giao diện lưu trữ. Một hàm duy nhất sẽ hoạt động với mọi kiểu lưu trữ, cho thấy giao diện cho phép các lớp hoàn toàn không liên quan có tính đa hình như thế nào.
Bạn sẽ sắp xếp code trong bốn tệp:
Storable.php: Định nghĩa giao diệnStorablevới hai chữ ký phương thức:save($key, $data)vàretrieve($key). Hợp đồng này đảm bảo mọi hệ thống lưu trữ đều có thể lưu và truy xuất dữ liệu, bất kể cách triển khai bên trong.FileStorage.php: Tạo lớpFileStoragetriển khaiStorable. Nhúng tệp giao diện. Lớp này cần có thuộc tính riêng tư$directory, được thiết lập thông qua hàm khởi tạo. Triển khaisave($key, $data)để trả về"Saving '[data]' to file [directory]/[key].txt". Triển khairetrieve($key)để trả về"Reading from file [directory]/[key].txt".DatabaseStorage.php: Tạo lớpDatabaseStoragecũng triển khaiStorable. Nhúng tệp giao diện. Lớp này cần có thuộc tính riêng tư$tableName, được thiết lập thông qua hàm khởi tạo. Triển khaisave($key, $data)để trả về"Inserting '[data]' into table [tableName] with key [key]". Triển khairetrieve($key)để trả về"Selecting from table [tableName] where key = [key]".main.php: Nhúng cả hai tệp lưu trữ. Tạo hàm có tênstoreData, nhận một tham số kiểuStorable, một khóa và dữ liệu. Hàm này cần trả về kết quả của lời gọisave()với khóa và dữ liệu đó. Tạo một hàm khác có tênfetchData, nhận một tham số kiểuStorablevà một khóa, rồi trả về kết quả của lời gọiretrieve().
Bạn sẽ nhận bốn đầu vào: đường dẫn thư mục, tên bảng, khóa và dữ liệu cần lưu. Tạo một đối tượng FileStorage với đường dẫn thư mục và một đối tượng DatabaseStorage với tên bảng. Dùng hàm storeData() để lưu dữ liệu trước bằng hệ thống lưu trữ tệp, sau đó bằng hệ thống lưu trữ cơ sở dữ liệu. In mỗi kết quả trên một dòng riêng. Tiếp đó, dùng fetchData() để truy xuất dữ liệu từ hệ thống lưu trữ tệp và in kết quả đó.
Hãy chú ý cách storeData() và fetchData() hoạt động giống hệt nhau với cả hai kiểu lưu trữ. Chúng chỉ cần đối tượng triển khai Storable. Hệ thống tệp và cơ sở dữ liệu có cách triển khai nội bộ hoàn toàn khác nhau, nhưng vẫn có thể thay thế cho nhau nhờ hợp đồng giao diện.
Tự làm thử
<?php
require_once 'FileStorage.php';
require_once 'DatabaseStorage.php';
// Đọc đầu vào
$directory = trim(fgets(STDIN));
$tableName = trim(fgets(STDIN));
$key = trim(fgets(STDIN));
$data = trim(fgets(STDIN));
// TODO: Tạo hàm (function) storeData nhận một Storable, khóa và dữ liệu
// Hàm cần trả về kết quả khi gọi save() với khóa và dữ liệu
// TODO: Tạo hàm fetchData nhận một Storable và khóa
// Hàm cần trả về kết quả khi gọi retrieve() với khóa
// TODO: Tạo một instance FileStorage với thư mục
// TODO: Tạo một instance DatabaseStorage với tên bảng
// TODO: Dùng storeData() để lưu dữ liệu vào tệp, rồi in ra kết quả
// TODO: Dùng storeData() để lưu dữ liệu vào cơ sở dữ liệu, rồi in ra kết quả
// TODO: Dùng fetchData() để lấy dữ liệu từ tệp, rồi in ra kết quả
?>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 sinh2Khô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