Menu
CoddyTech

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.

challenge icon

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ên PatternCategory, đạ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"
  • PatternClassifier.h: Tạo một lớp PatternClassifier có 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ỏ đến PatternCategory phù 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.

  • 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 PatternClassifier và 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 mechanisms

Với đầu vào Observer:

Observer is a Behavioral pattern
Purpose: Object interaction and responsibility

Với đầu vào Proxy:

Unknown pattern: Proxy

Thử 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;
}
quiz iconTự kiểm tra

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

Tự luyện tập: Trình biên dịch C++ online