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 C# của Coddy. Bài học 59 trên 70.
Mẫu thiết kế Template Method là một mẫu thiết kế hành vi, xác định khung của một 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ở kiểm soát quy trình, còn các lớp dẫn xuất tùy chỉnh từng phần.
Mẫu này sử dụng tính kế thừa và các phương thức trừu tượng. Lớp cơ sở chứa một “phương thức khuôn mẫu” gọi một chuỗi bước, trong đó một số bước là trừu tượng và các lớp con phải triển khai:
public abstract class DataProcessor
{
// Phương thức mẫu (template method): xác định cấu trúc thuật toán (algorithm)
public void Process()
{
ReadData();
ProcessData();
SaveData();
}
protected abstract void ReadData();
protected abstract void ProcessData();
protected virtual void SaveData() => Console.WriteLine("Saving to default location");
}
public class CsvProcessor : DataProcessor
{
protected override void ReadData() => Console.WriteLine("Reading CSV file");
protected override void ProcessData() => Console.WriteLine("Parsing CSV data");
}
public class JsonProcessor : DataProcessor
{
protected override void ReadData() => Console.WriteLine("Reading JSON file");
protected override void ProcessData() => Console.WriteLine("Parsing JSON data");
protected override void SaveData() => Console.WriteLine("Saving to cloud");
}Mỗi lớp con cung cấp cách triển khai riêng, còn lớp cơ sở quy định thứ tự thực hiện:
DataProcessor csv = new CsvProcessor();
csv.Process();
// Đọc tệp CSV
// Phân tích dữ liệu CSV
// Lưu vào vị trí mặc định
DataProcessor json = new JsonProcessor();
json.Process();
// Đọc tệp JSON
// Phân tích dữ liệu JSON
// Lưu lên đám mâyMẫu Template Method phù hợp khi nhiều lớp dùng chung cấu trúc thuật toán (algorithm) nhưng khác nhau ở một số bước cụ thể. Mẫu này giúp tái sử dụng code bằng cách đặt logic chung trong lớp cơ sở, đồng thời vẫn linh hoạt nhờ các phương thức (methods) có thể ghi đè.
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 thiết kế Template Method. Các loại báo cáo khác nhau, chẳng hạn như báo cáo doanh số và báo cáo tồn kho, có cùng cấu trúc tổng thể: tất cả đều cần thu thập dữ liệu, định dạng dữ liệu và xuất kết quả, nhưng mỗi loại báo cáo xử lý các bước này theo cách khác nhau.
Bạn sẽ sắp xếp code trong ba tệp:
ReportGenerator.cs: Tạo lớp trừu tượngReportGeneratortrong không gian tênReporting. Lớp cơ sở này định nghĩa khung của thuật toán tạo báo cáo thông qua một phương thức khuôn mẫu có tênGenerate(). Phương thức này cần gọi lần lượt ba bước:GatherData(),FormatReport()vàOutputReport(). ĐặtGatherData()vàFormatReport()thành phương thức trừu tượng, vì mỗi loại báo cáo sẽ triển khai chúng theo cách khác nhau, cònOutputReport()là phương thức ảo có phần triển khai mặc định để in raSending to default printer.ConcreteReports.cs: Tạo hai lớp báo cáo cụ thể trong cùng không gian tên, kế thừa từReportGenerator:SalesReport: triển khaiGatherData()để in raCollecting sales data from databasevàFormatReport()để in raFormatting as sales summaryInventoryReport: triển khaiGatherData()để in raScanning warehouse inventory,FormatReport()để in raFormatting as inventory listvà ghi đèOutputReport()để in raSending to warehouse manager
Program.cs: Kết hợp mọi thứ bằng cách tạo các đối tượng báo cáo và tạo báo cáo. Phương thức khuôn mẫu đảm bảo mỗi báo cáo tuân theo cùng một quy trình ba bước, nhưng cách thực hiện cụ thể của mỗi bước sẽ thay đổi tùy theo loại báo cáo.
Bạn sẽ nhận một đầu vào:
- Loại báo cáo:
saleshoặcinventory
Dựa trên đầu vào, hãy tạo bộ tạo báo cáo phù hợp và gọi phương thức Generate() của nó.
Ví dụ, nếu đầu vào là sales, đầu ra sẽ là:
Collecting sales data from database
Formatting as sales summary
Sending to default printerNếu đầu vào là inventory, đầu ra sẽ là:
Scanning warehouse inventory
Formatting as inventory list
Sending to warehouse managerHãy lưu ý rằng cả hai báo cáo đều tuân theo cùng một cấu trúc thuật toán chính xác: thu thập, định dạng, xuất, nhưng phần triển khai của từng bước được tùy chỉnh. SalesReport dùng hành vi xuất mặc định, còn InventoryReport ghi đè hành vi đó. Điều này cho thấy mẫu thiết kế Template Method giúp bạn kiểm soát những bước nào bắt buộc phải ghi đè và những bước nào có thể tùy chỉnh!
Tự làm thử
using System;
using Reporting;
class Program
{
public static void Main(string[] args)
{
string reportType = Console.ReadLine();
// TODO: Tạo đối tượng tạo báo cáo phù hợp dựa trên reportType
// Nếu reportType là "sales", tạo một SalesReport
// Nếu reportType là "inventory", tạo một InventoryReport
// Sau đó gọi phương thức (method) Generate() trên đối tượng báo cáo
}
}
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
1Các khái niệm cơ bản về lập trình hướng đối tượng
Tệp bên ngoàiKhông gian tên và chỉ thịGiới thiệu về lớp và đối tượngTừ khóa thisPhương thức và tham sốTrường và thuộc tínhHàm khởi tạoKhởi tạo đối tượngÔn tập: Máy tính đơn giản4Kế thừa
Cú pháp kế thừa cơ bản (:)Từ khóa 'base'Từ khóa virtual và overrideLớp sealedLớp cơ sở 'object'Ôn tập: hệ phân cấp nhân viên7Tính năng nâng cao
Nạp chồng toán tửBộ lập chỉ mục (this[])Ghi đè ToString()Phương thức mở rộngÔn tập: Danh sách tùy chỉnh10Các mẫu thiết kế phần 1
Giới thiệu về mẫu thiết kếSingleton an toàn với luồngMẫu FactoryMẫu Observer (sự kiện)Mẫu Strategy2Thuộc tính và thành viên tĩnh
Thuộc tính tự độngThuộc tính chỉ đọc hoặc chỉ ghiTrường và phương thức tĩnhLớp tĩnhThành viên có thân biểu thức5Đa hình và interface
Đa hình lúc biên dịch và lúc chạyInterface và lớp trừu tượngNhiều interfaceInterface tường minhUpcasting và downcastingÔn tập: bộ tính toán hình học8Các khái niệm OOP nâng cao
Ưu tiên composition hơn kế thừaGenerics (lớp và phương thức)Delegate và sự kiệnAttribute và reflectionGiao diện IDisposable và câu lệnh usingKiến thức cơ bản về dependency injection11Các mẫ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ợpTự luyện tập: Trình biên dịch C# online