Giới thiệu về mẫu thiết kế
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 90 trên 104.
Mẫu thiết kế là những giải pháp đã được kiểm chứng và có thể tái sử dụng cho các vấn đề thường gặp trong thiết kế phần mềm. Chúng không phải là đoạn code để bạn sao chép trực tiếp, mà là các khuôn mẫu hoặc bản thiết kế mô tả cách cấu trúc lớp và đối tượng để giải quyết những thử thách cụ thể một cách tinh tế.
Khái niệm này trở nên phổ biến nhờ “Gang of Four” (GoF) trong cuốn sách xuất bản năm 1994, giới thiệu 23 mẫu thiết kế cơ bản. Những mẫu thiết kế này thường được chia thành ba nhóm:
| Nhóm | Mục đích | Ví dụ |
|---|---|---|
| Khởi tạo | Cơ chế tạo đối tượng | Singleton, Factory, Builder |
| Cấu trúc | Kết hợp lớp và đối tượng | Adapter, Decorator, Composite |
| Hành vi | Tương tác và trách nhiệm của đối tượng | Observer, Strategy, Command |
Tại sao nên học mẫu thiết kế? Chúng tạo ra một vốn từ chung giữa các nhà phát triển, câu nói "dùng Factory ở đây" giúp truyền đạt ngay một ý tưởng phức tạp. Chúng cũng giúp bạn tránh phải tự tìm lại giải pháp và khiến code linh hoạt, dễ bảo trì hơn.
Trong C++, các mẫu thiết kế tận dụng những tính năng của lập trình hướng đối tượng mà bạn đã học: kế thừa, tính đa hình, lớp trừu tượng và mẫu. Trong những bài học tiếp theo, bạn sẽ triển khai một số mẫu thiết kế thiết yếu và hiểu khi nào nên dùng từng mẫu.
Thử thách
DễHãy xây dựng một bộ phân loại mẫu đơn giản để thể hiện hiểu biết của bạn về ba nhóm mẫu thiết kế. Bạn sẽ tạo một hệ thống nhận tên mẫu và xác định mẫu đó thuộc nhóm nào: Creational, Structural hay Behavioral, đồng thời đưa ra mô tả ngắn về mục đích của nhóm đó.
Bạn sẽ sắp xếp code trong ba tệp:
PatternCategory.h: Định nghĩa một lớp cơ sở trừu tượng có tênPatternCategory, đại diện cho một nhóm mẫu thiết kế. Lớp này cần có:- Một phương thức ảo thuần túy
getName(), trả về tên nhóm dưới dạng chuỗi - Một phương thức ảo thuần túy
getPurpose(), trả về mô tả về chức năng của các mẫu trong nhóm này - Một hàm hủy ảo
Sau đó, tạo ba lớp dẫn xuất kế thừa từ
PatternCategory:CreationalCategory: trả về tên"Creational"và mục đích"Object creation mechanisms"StructuralCategory: trả về tên"Structural"và mục đích"Class and object composition"BehavioralCategory: trả về tên"Behavioral"và mục đích"Object interaction and responsibility"
- Một phương thức ảo thuần túy
PatternClassifier.h: Tạo một lớpPatternClassifiercó thể xác định một mẫu cho trước thuộc nhóm nào.Bộ phân loại của bạn cần có phương thức
classify, nhận tên mẫu (chuỗi) và trả về con trỏ đếnPatternCategoryphù hợp. Hãy dùng con trỏ thông minh (std::unique_ptr) để quản lý bộ nhớ.Bộ phân loại cần nhận biết các mẫu sau:
- Creational:
Singleton,Factory,Builder - Structural:
Adapter,Decorator,Composite - Behavioral:
Observer,Strategy,Command
Nếu không nhận ra tên mẫu, hãy trả về
nullptr.- Creational:
main.cpp: Đọc một đầu vào duy nhất: tên của một mẫu thiết kế.Tạo một
PatternClassifiervà dùng nó để phân loại mẫu đầu vào. Nếu nhận ra mẫu, hãy in ra:[PatternName] is a [CategoryName] pattern Purpose: [CategoryPurpose]Nếu không nhận ra mẫu, hãy in ra:
Unknown pattern: [PatternName]
Ví dụ, với đầu vào Singleton:
Singleton is a Creational pattern
Purpose: Object creation mechanismsVới đầu vào Observer:
Observer is a Behavioral pattern
Purpose: Object interaction and responsibilityVới đầu vào Proxy:
Unknown pattern: ProxyThử thách này giúp bạn củng cố kiến thức về ba nhóm mẫu thiết kế, đồng thời luyện tập kế thừa, tính đa hình và con trỏ thông minh: tất cả đều là những khái niệm bạn đã nắm vững. Cấu trúc nhiều tệp mô phỏng cách các dự án thực tế sắp xếp những lớp có liên quan.
Tự làm thử
#include <iostream>
#include <string>
#include "PatternClassifier.h"
int main() {
// Đọc tên mẫu
std::string patternName;
std::cin >> patternName;
// TODO: Tạo một instance của PatternClassifier
// TODO: Dùng bộ phân loại để phân loại mẫu đầu vào (input)
// TODO: Nếu nhận diện được mẫu, in ra:
// "[PatternName] is a [CategoryName] pattern"
// "Purpose: [CategoryPurpose]"
// TODO: Nếu không nhận diện được mẫu (nullptr), in ra:
// "Unknown pattern: [PatternName]"
return 0;
}
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àiBiên dịch và tạo bản dựng C++Tệp header và tệp nguồnNamespace và phạm viGiới thiệu về OOP trong C++Lớp và đối tượngCon trỏ thisPhương thức (hàm thành viên)Thuộc tính (dữ liệu thành viên)Cơ bản về hàm khởi tạo và hàm hủyÔn tập: máy tính đơn giản4Thuộc tính của lớp
Thành viên đối tượng và thành viên tĩnhHàm truy xuất và hàm thiết lậpHàm thành viên hằngTừ khóa mutablePhương thức và biến tĩnhHàm và lớp bạnÔn tập: Trình quản lý tài khoản ngân hàng7Kế thừa
Kế thừa cơ bảnMức truy cập trong kế thừaThứ tự gọi hàm khởi tạo và hàm hủyGhi đè phương thứcHàm ảo và VTableĐa kế thừaKế thừa ảoÔn tập: hệ phân cấp nhân viên10Tổng quan về STL
Tổng quan và triết lý của STLCác vùng chứa của STLBộ lặpCác thuật toán của STLHàm tử và biểu thức lambdaÔn tập: tần suất từ13Mẫu thiết kế phần 1
Giới thiệu về mẫu thiết kếMẫu SingletonFactory và Abstract FactoryMẫu BuilderMẫu ObserverMẫu Strategy2Quản lý bộ nhớ
Bộ nhớ ngăn xếp và heapCon trỏ và tham chiếuBộ nhớ động (new/delete)Con trỏ thông minh trong C++RAII trong C++Ôn tập: Trình quản lý mảng động5Tính đóng gói
Phạm vi truy cập trong C++Tìm hiểu sâu về phạm vi truy cậpẨn thông tinStruct và lớpLớp lồng nhau và lớp bên trongÔn tập: hệ thống hồ sơ sinh viên8Đa hình
Đa hình lúc biên dịch và khi chạyNạp chồng hàmÔn lại hàm ảoHàm ảo thuần túyLớp trừu tượngThiết kế interface trong C++Ép kiểu động và RTTIÔn tập: Máy tính hình học3Hàm khởi tạo và hàm hủy
Hàm khởi tạo mặc địnhHàm khởi tạo có tham sốHàm khởi tạo sao chépHàm khởi tạo di chuyểnDanh sách khởi tạoHàm khởi tạo ủy quyềnTìm hiểu sâu về hàm hủyQuy tắc 3 / 5 / 0Ôn tập: lớp chuỗi6Nạp chồng toán tử
Giới thiệu về nạp chồng toán tửNạp chồng toán tử số họcNạp chồng toán tử so sánhToán tử luồngNạp chồng toán tử gánNạp chồng toán tử [] và ()Toán tử chuyển đổi kiểuÔn tập: lớp ma trận9Mẫu
Mẫu hàmMẫu lớpChuyên biệt hóa mẫuMẫu biến tham sốCơ bản về SFINAE và đặc điểm kiểuÔn tập: vùng chứa tổng quátTự luyện tập: Trình biên dịch C++ online