Mẫu phương thức khuôn mẫu
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 78 trên 91.
Mẫu phương thức là một mẫu thiết kế hành vi, xác định khung sườn của thuật toán trong lớp cơ sở, cho phép các lớp con ghi đè những bước cụ thể mà không làm thay đổi cấu trúc tổng thể. Lớp cơ sở điều khiển quy trình, còn các lớp con tùy chỉnh từng phần riêng lẻ.
Hãy nghĩ đến việc tạo nhiều loại tài liệu khác nhau.
Mọi tài liệu đều tuân theo cùng một quy trình: tạo phần đầu, thêm nội dung, tạo phần chân. Nhưng chi tiết của mỗi bước sẽ khác nhau tùy theo loại tài liệu. Phương thức mẫu xác định trình tự này, còn các lớp con triển khai từng chi tiết.
<?php
abstract class DocumentGenerator {
// Phương thức khuôn mẫu (template method) xác định cấu trúc thuật toán (algorithm)
public final function generate(): string {
$output = $this->createHeader();
$output .= $this->createContent();
$output .= $this->createFooter();
return $output;
}
// Các bước mà lớp con (subclass) cần triển khai
abstract protected function createHeader(): string;
abstract protected function createContent(): string;
abstract protected function createFooter(): string;
}
class HtmlDocument extends DocumentGenerator {
protected function createHeader(): string {
return "<html><head></head><body>";
}
protected function createContent(): string {
return "<p>Hello World</p>";
}
protected function createFooter(): string {
return "</body></html>";
}
}
class TextDocument extends DocumentGenerator {
protected function createHeader(): string {
return "=== DOCUMENT ===\n";
}
protected function createContent(): string {
return "Hello World\n";
}
protected function createFooter(): string {
return "=== END ===";
}
}
$html = new HtmlDocument();
echo $html->generate() . "\n";
$text = new TextDocument();
echo $text->generate();
Đầu ra:
<html><head></head><body><p>Hello World</p></body></html>
=== DOCUMENT ===
Hello World
=== END ===Hãy chú ý đến từ khóa final trong phương thức mẫu. Từ khóa này ngăn các lớp con thay đổi cấu trúc của thuật toán. Mẫu này phù hợp khi bạn có nhiều lớp tuân theo cùng một quy trình nhưng khác nhau về chi tiết triển khai. Để thêm một loại tài liệu mới, bạn chỉ cần tạo một lớp con mà không cần sửa code hiện có.
Thử thách
DễHãy xây dựng một hệ thống tạo báo cáo bằng Mẫu Template Method. Các loại báo cáo khác nhau có cùng cấu trúc, gồm phần tiêu đề, phần dữ liệu và phần tóm tắt, nhưng mỗi loại định dạng các phần này theo cách riêng. Phương thức mẫu sẽ xác định quy trình này, còn các lớp con tùy chỉnh từng bước.
Bạn sẽ sắp xếp code trong bốn tệp:
ReportGenerator.php: Tạo lớp trừu tượngReportGeneratorđể định nghĩa khung sườn của thuật toán tạo báo cáo. Lớp của bạn cần:- Nhận tiêu đề báo cáo trong hàm khởi tạo (dùng tính năng khai báo thuộc tính trong hàm khởi tạo)
- Có phương thức công khai
finalgenerate(): string, gọi lần lượt ba bước:createTitle(),createBody()vàcreateSummary(), rồi nối các kết quả lại - Khai báo ba phương thức trừu tượng có phạm vi protected mà các lớp con phải triển khai:
createTitle(): string,createBody(): stringvàcreateSummary(): string
HtmlReport.php: Nạp tệp ReportGenerator và tạo lớpHtmlReportkế thừa lớp đó. Báo cáo này định dạng đầu ra dưới dạng HTML:createTitle()trả về"<h1>[title]</h1>"createBody()trả về"<p>Report data goes here</p>"createSummary()trả về"<footer>End of report</footer>"
PlainTextReport.php: Nạp tệp ReportGenerator và tạo lớpPlainTextReportkế thừa lớp đó. Báo cáo này dùng định dạng văn bản đơn giản:createTitle()trả về"### [title] ###\n"createBody()trả về"Report data goes here\n"createSummary()trả về"--- End of report ---"
main.php: Nạp cả hai tệp báo cáo. Bạn sẽ nhận hai đầu vào: loại báo cáo ("html"hoặc"text") và tiêu đề báo cáo.Dựa trên loại báo cáo, hãy tạo bộ tạo báo cáo phù hợp với tiêu đề đã cho. Gọi
generate()và in toàn bộ báo cáo.
Mẫu Template Method đảm bảo mọi báo cáo đều tuân theo cùng cấu trúc ba bước, đồng thời cho phép mỗi loại báo cáo định dạng riêng từng phần. Từ khóa final trong generate() ngăn các lớp con thay đổi trình tự của thuật toán. Chúng chỉ có thể tùy chỉnh từng bước riêng lẻ.
Tự làm thử
<?php
require_once 'HtmlReport.php';
require_once 'PlainTextReport.php';
// Đọc đầu vào
$reportType = trim(fgets(STDIN));
$reportTitle = trim(fgets(STDIN));
// TODO: Dựa vào loại báo cáo ("html" hoặc "text"),
// tạo trình tạo báo cáo phù hợp với tiêu đề đã cho
// TODO: Gọi generate() và in ra báo cáo đầy đủ
?>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