Table of contents
Mỗi pattern mô tả một vấn đề xảy ra lặp đi lặp lại, và trình bày trọng tâm của giải pháp cho vấn đề đó, theo cách mà bạn có thể dùng đi dùng lại hàng triệu lần mà không cần phải suy nghĩ.
— Christopher Alexander —
Design Patterns là gì?
Design pattern là các giải pháp tiêu biểu cho những vấn đề thường gặp trong thiết kế phần mềm. Chúng giống như các bản thiết kế có sẵn mà bạn có thể tùy chỉnh để giải quyết những vấn đề lặp lại trong code của mình.
Bạn không thể chỉ đơn giản tìm một pattern và sao chép nó vào chương trình của mình giống như việc sử dụng các hàm hoặc thư viện có sẵn. Pattern không phải là một đoạn code cụ thể mà là một khái niệm tổng quát để giải quyết một vấn đề cụ thể. Bạn cần dựa trên chi tiết của pattern để triển khai một giải pháp phù hợp với thực tế của chương trình mình.
Pattern thường bị nhầm lẫn với thuật toán, vì cả hai đều mô tả các giải pháp điển hình cho những vấn đề đã biết. Tuy nhiên, trong khi thuật toán luôn định nghĩa một chuỗi hành động rõ ràng để đạt được mục tiêu, pattern lại là một mô tả cấp cao hơn về giải pháp. Code của cùng một pattern có thể được áp dụng khác nhau trong hai chương trình khác nhau.
Ví dụ minh họa: Một thuật toán có thể được so sánh với công thức nấu ăn, vì cả hai đều có các bước rõ ràng để đạt được mục tiêu. Trong khi đó, một pattern giống như bản thiết kế: bạn có thể hình dung được kết quả và các đặc điểm của nó, nhưng trình tự triển khai cụ thể sẽ do bạn quyết định.
Một pattern bao gồm những gì?
Hầu hết các pattern đều được mô tả rất chi tiết để có thể tái sử dụng trong nhiều ngữ cảnh khác nhau. Dưới đây là các thành phần thường có trong mô tả của một pattern:
Intent: Mô tả ngắn gọn vấn đề và giải pháp mà pattern hướng tới.
Motivation: Giải thích sâu hơn về vấn đề và cách mà pattern giúp giải quyết vấn đề đó.
Structure: Mô tả cấu trúc các lớp, chỉ ra từng phần của pattern và mối quan hệ giữa chúng.
Code example: Đưa ra ví dụ code trong một ngôn ngữ lập trình phổ biến để giúp bạn dễ dàng nắm bắt ý tưởng của pattern.
Một số danh mục pattern còn cung cấp các chi tiết hữu ích khác, chẳng hạn như: phạm vi áp dụng của pattern, các bước triển khai, và mối liên hệ với các pattern khác.
History of patterns
Ai đã phát minh ra các pattern?
Đây là một câu hỏi hay, nhưng không hoàn toàn chính xác. Design pattern không phải là những khái niệm khó hiểu hay phức tạp – trái lại, chúng là các giải pháp điển hình cho những vấn đề thường gặp trong thiết kế hướng đối tượng. Khi một giải pháp được lặp đi lặp lại trong nhiều dự án, cuối cùng sẽ có người đặt tên cho nó và mô tả chi tiết cách áp dụng. Đó chính là cách một pattern được phát hiện.
Khái niệm về pattern lần đầu tiên được mô tả bởi Christopher Alexander trong cuốn sách A Pattern Language: Towns, Buildings, Construction. Cuốn sách này đề cập đến một "ngôn ngữ" để thiết kế môi trường đô thị, với các đơn vị cơ bản là các pattern. Các pattern này có thể mô tả những yếu tố như: độ cao của cửa sổ, số tầng của một tòa nhà, kích thước của các khu vực cây xanh trong khu phố, v.v.
Ý tưởng này sau đó được tiếp nhận bởi bốn tác giả: Erich Gamma, John Vlissides, Ralph Johnson, và Richard Helm. Năm 1994, họ xuất bản cuốn sách Design Patterns: Elements of Reusable Object-Oriented Software, áp dụng khái niệm design pattern vào lập trình. Cuốn sách giới thiệu 23 pattern để giải quyết các vấn đề trong thiết kế hướng đối tượng và nhanh chóng trở thành một hiện tượng. Do tên sách khá dài, mọi người bắt đầu gọi nó là "cuốn sách của nhóm bốn người" (the book by the gang of four), sau đó được rút gọn thành GoF book.
Kể từ đó, hàng chục pattern khác trong thiết kế hướng đối tượng đã được phát hiện. Phương pháp tiếp cận dựa trên pattern cũng trở nên phổ biến trong các lĩnh vực lập trình khác, dẫn đến sự ra đời của nhiều pattern nằm ngoài phạm vi thiết kế hướng đối tượng.
Why should I learn patterns?
Có cần thiết phải học design pattern?
Thực tế là bạn có thể làm lập trình viên trong nhiều năm mà không hề biết đến bất kỳ design pattern nào. Rất nhiều người làm việc theo cách này. Tuy nhiên, ngay cả trong trường hợp đó, bạn có thể đã vô tình áp dụng một số pattern mà không nhận ra. Vậy tại sao bạn nên dành thời gian để học chúng?
Design pattern là một bộ công cụ gồm những giải pháp đã được kiểm chứng cho các vấn đề phổ biến trong thiết kế phần mềm. Ngay cả khi bạn không gặp phải những vấn đề đó, việc biết về các pattern vẫn rất hữu ích vì nó giúp bạn học cách giải quyết nhiều loại vấn đề khác nhau dựa trên các nguyên tắc thiết kế hướng đối tượng.
Hơn nữa, design pattern cung cấp một ngôn ngữ chung giúp bạn và đồng đội giao tiếp hiệu quả hơn. Bạn có thể nói, "Hãy sử dụng Singleton cho trường hợp này," và mọi người sẽ hiểu ngay ý tưởng đằng sau đề xuất của bạn. Không cần phải giải thích Singleton là gì nếu mọi người đều biết đến pattern và tên gọi của nó.
Criticism of patterns
Dường như chỉ có những người lười biếng mới chưa từng chỉ trích design pattern. Dưới đây là một số lập luận phổ biến nhất chống lại việc sử dụng pattern:
Giải pháp tạm bợ cho ngôn ngữ lập trình yếu
Thông thường, nhu cầu sử dụng pattern xuất hiện khi lập trình viên chọn một ngôn ngữ hoặc công nghệ không cung cấp đủ mức độ trừu tượng cần thiết. Trong trường hợp này, các pattern trở thành giải pháp tạm bợ (kludge) để bổ sung những khả năng mà ngôn ngữ thiếu.
Ví dụ, pattern Strategy có thể được triển khai một cách đơn giản bằng hàm ẩn danh (anonymous function hoặc lambda) trong hầu hết các ngôn ngữ lập trình hiện đại.
Giải pháp kém hiệu quả
Design pattern cố gắng hệ thống hóa những cách tiếp cận đã được sử dụng rộng rãi. Tuy nhiên, việc thống nhất hóa này lại bị nhiều người coi như một giáo điều. Họ áp dụng các pattern một cách máy móc, "đúng theo sách vở", mà không điều chỉnh phù hợp với ngữ cảnh của dự án.
Sử dụng không cần thiết
"Nếu tất cả những gì bạn có chỉ là một cái búa, mọi thứ đều trông giống như một cái đinh."
Đây là vấn đề thường gặp với những người mới học về design pattern. Sau khi làm quen với các pattern, họ cố gắng áp dụng chúng ở khắp mọi nơi, ngay cả trong những tình huống mà giải pháp đơn giản hơn đã đủ đáp ứng nhu cầu.
Classification of patterns
Năm 1994, bốn tác giả Erich Gamma, Richard Helm, Ralph Johnson và John Vlissides đã cho xuất bản một cuốn sách với tiêu đề Design Patterns – Elements of Reusable Object-Oriented Software, đây là khởi nguồn của khái niệm design pattern trong lập trình phần mềm.
Bốn tác giả trên được biết đến rộng rãi dưới tên Gang of Four (bộ tứ). Theo quan điểm của bốn người, design pattern chủ yếu được dựa theo những quy tắc sau đây về thiết kế hướng đối tượng.
Lập trình cho interface chứ không phải để implement interface đó.
Ưu tiên object composition hơn là thừa kế.
Hệ thống các mẫu Design pattern hiện có 23 mẫu được định nghĩa trong cuốn “Design patterns Elements of Reusable Object Oriented Software” và được chia thành 3 nhóm:
Creational Pattern (nhóm khởi tạo – 5 mẫu) gồm: Factory Method, Abstract Factory, Builder, Prototype, Singleton. Những Design pattern loại này cung cấp một giải pháp để tạo ra các object và che giấu được logic của việc tạo ra nó, thay vì tạo ra object một cách trực tiếp bằng cách sử dụng method new. Điều này giúp cho chương trình trở nên mềm dẻo hơn trong việc quyết định object nào cần được tạo ra trong những tình huống được đưa ra.
Structural Pattern (nhóm cấu trúc – 7 mẫu) gồm: Adapter, Bridge, Composite, Decorator, Facade, Flyweight và Proxy. Những Design pattern loại này liên quan tới class và các thành phần của object. Nó dùng để thiết lập, định nghĩa quan hệ giữa các đối tượng.
Behavioral Pattern (nhóm tương tác/ hành vi – 11 mẫu) gồm: Interpreter, Template Method, Chain of Responsibility, Command, Iterator, Mediator, Memento, Observer, State, Strategy và Visitor. Nhóm này dùng trong thực hiện các hành vi của đối tượng, sự giao tiếp giữa các object với nhau.
The Catalog of Design Patterns
Creational patterns
Cung cấp các cơ chế tạo đối tượng, giúp tăng tính linh hoạt và khả năng tái sử dụng của mã nguồn.
Java Design Pattern | Status |
Singleton | Done |
Factory Method | Done |
Abstract Factory | Done |
Builder | Done |
Prototype | Done |
Object Pool | Done |
Structural patterns
- Giải thích cách tổ chức các đối tượng và lớp thành các cấu trúc lớn hơn, đồng thời đảm bảo các cấu trúc này linh hoạt và hiệu quả.
Java Design Pattern | Status |
Adapter | Done |
Bridge | In progress |
Composite | Waiting |
Decorator | Waiting |
Facade | Waiting |
Flyweight | Waiting |
Proxy | Waiting |
Behavioral patterns
- Xử lý việc giao tiếp hiệu quả và phân công trách nhiệm giữa các đối tượng.
- | Java Design Pattern | Status | | --- | --- | | Chain of Responsibility | Waiting | | Command | Waiting | | Interpreter | Waiting | | Iterator | Waiting | | Mediator | Waiting | | Memento | Waiting | | Observer | Waiting | | State | Waiting | | Strategy | Waiting | | Template Method | Waiting | | Visitor | Waiting |