Cùng tìm hiểu về "DESIGN PATTERNS"
Design patterns cung cấp các giải pháp cho các vấn đề thường gặp trong việc phát triển. Chúng chỉ đơn thuần là các khái niệm có thể được sử dụng để xử lý các vấn đề thường gặp bằng một cách tối ưu nhất có thể.
Giới thiệu
Design patterns là một phần cơ bản trong việc phát triển phẩn mềm, chúng cung cấp các giải pháp cho các vấn đề thường gặp trong việc phát triển. Thay vì đưa ra các giải pháp cụ thể, design patterns chỉ đơn thuần là các khái niệm có thể được sử dụng để xử lý các vấn đề thường gặp bằng một cách tối ưu nhất có thể.
Design Patterns không phải là ngôn ngữ cụ thể nào cả. Nó có thể thực hiện được ở phần lớn các ngôn ngữ lập trình, chẳng hạn như Java, C#, thậm chí là Javascript hay bất kỳ ngôn ngữ lập trình nào khác.
Tại sao phải sử dụng Design Patterns?
Khi xây dựng một ứng dụng, chúng ta thường phải đối mặt với các vấn đề phức tạp như quản lý trạng thái, tương tác giữa các đối tượng, hoặc cách tổ chức mã nguồn sao cho dễ bảo trì. Design patterns giúp giải quyết các vấn đề này bằng cách cung cấp các mô hình được kiểm chứng và giải pháp sẵn có.
- Giúp việc tái sử dụng và dễ dàng mở rộng code.
- Cung cấp các giải pháp ở dạng tổng quát, giúp tăng tốc độ phát triển.
- Tránh được các bug tiềm ẩn do đã được kiểm nghiệm kỹ càng.
3 Nhóm Design Patterns
Creational (Khởi tạo): cung cấp nhiều cơ chế khởi tạo đối tượng, giúp tăng tính linh hoạt và tái sử dụng code.
o Singleton: đảm bảo rằng class này chỉ có một phiên bản, đồng thời mọi truy cập đến nó đều là ở mức toàn cục (có thể truy cập ở bất kỳ đâu).
o Prototype: đảm bảo cho việc sao chép các đối tượng hiện có mà không làm cho chúng phụ thuộc vào các lớp sở thuộc.
o Builder: giúp việc xây dựng các đối tượng phức tạp theo từng bước. Parttern này cho phép bạn tạo ra các loại và phiên bản khác nhau của một đối tượng sử dụng cùng cấu trúc.
o Abstract Factory: một interface có nhiệm vụ tạo ra một “nhà máy” của các object có liên quan tới nhau mà không cần phải chỉ ra trực tiếp class của object.
o Factory Method: quản lý và trả về các đối tượng theo yêu cầu, giúp việc khởi tạo đối tượng một cách linh hoạt hơn.
Structural (Cấu trúc): giải thích cách mà làm sao để tập hợp các đối tượng và class thành một đối tượng có cấu trúc lớn hơn, đồng thời giữ cho các cấu trúc này linh hoạt và hiệu quả.
o Adapter: cho phép các đối tượng không tương thích làm việc với nhau.
o Bridge: giúp việc phân tách một class lớn hoặc một tập hợp của các class liên quan tới nhau thành 2 phần riêng biệt là “trừu tượng – hiện thực”. Giúp cho việc phát triển độc lập giữa các đối tượng này.
o Composite: cho phép kết hợp các object tương tự nhau và thao tác các đối tượng này như một đối tượng duy nhất.
o Decorator: cho phép gắn hành động mới vào đối tượng bằng cách cho đói tượng đó vào một object đóng gói đặc biệt có chứa hành động đó.
o Facade: cung cấp một interface đơn giản, giúp che giấu các xử lý phức tạp phía sau nó.
o Flyweight: cho phép bạn điền nhiều object vào số lượng RAM có sẵn, bằng cách chia sẻ các phần trạng thái chung giữa các object thay vì việc giữ các trạng thái chung đó ở mỗi object.
o Proxy: giúp bạn cung cấp một đối tượng uỷ quyền hoặc đối tượng thay thế cho các đối tượng khác. Đối tượng được uỷ quyền này sẽ kiểm soát việc truy cập vào đối tượng gốc, cho phép bạn thực hiện điều gì đó trước hoặc sau khi yêu cầu được đưa đến đối tượng gốc.
Behavioral (Hành vi): liên quan đến các thuật toán và phân công trách nghiệm giữa các object
o Chain of Responsibility: cho phép đối tượng gửi yêu cầu thông qua một chuỗi các xử lý. Khi nhận được request, mỗi trình xử lý sẽ quyết định xử lý yêu cầu đó hay chuyển yêu cầu đó đến trình xử lý tiếp theo trong chuỗi.
o Command: biến request thành một đối tượng độc lập chứa tất cả các thông tin về request đó. Mỗi đối tượng này chứa thông tin đầy đủ về yêu cầu, bao gồm cả các tham số và phương thức cần thiết để thực hiện yêu cầu đó.
o Iterator: cung cấp cách thức để truy cập tới các phần tử của một tập hợp (list, array, stack, tree, ...) mà không cần phải tạo riêng các phương pháp truy cập cho từng tập hợp này.
o Mediator: giảm sự phức tạp trong việc giao tiếp giữa các đối tượng. Giảm thiểu sự giao tiếp trực tiếp giữa các đối tượng bằng cách chuyển các thông tin giữa các thành phần thông qua một đối tượng trung gian.
o Memento: cho phép lưu hoặc hoàn tác trạng thái cũ của một object mà không làm thay đổi thông tin hoặc cấu trúc của đối tượng ban đầu.
o Observer: duy trì các đối tượng phụ thuộc và thông báo cho chúng mỗi khi trạng thái thay đổi để cách thành phần phụ thuộc này có thể cập nhật một cách tự động.
o State: cho phép object thay đổi hành vi khi trạng thái nội bộ của nó thay đổi. Tách biệt các trạng thái thành các lớp riêng biệt và cho phép đối tượng chuyển đổi giữa các trạng thái một cách linh hoạt.
o Strategy: cho phép định nghĩa tập hợp của các phép thuật toán và đóng gói chúng lại vào một class riêng biệt. Điều này cho phép các thuật toán có thể được chọn linh hoạt tại thời điểm chạy mà không cần thay đổi mã nguồn.
o Template method: định nghĩa ra một khuân mẫu cho một thuật toán trong một supperclass nhưng cho phép các class con có thể ghi đè phương thức này mà không làm thay đổi cấu trúc của thuật toán.
o Visitor: cho phép định nghĩa các thao tác trên một tập hợp các đối tượng không đồng nhất về kiểu mà không làm thay đổi định nghĩa về đối tượng đó.
Kết luận
Trong bài viết này mình đã giới thiệu sơ qua các mẫu design patterns hiện có. Nhớ rằng, mỗi pattern có thể phù hợp với một tình huống cụ thể và không phải lúc nào cũng là lựa chọn tốt nhất. Quan trọng nhất là áp dụng chúng một cách có hiểu biết và linh hoạt, để đảm bảo rằng mã nguồn của chúng ta luôn đáp ứng được yêu cầu và dễ dàng bảo trì trong tương lai.
Ở bài viết sau chúng ta sẽ đi vào chi tiết các từng pattern và các trường hợp phổ biến hay dùng và tác dụng của pattern đó mang lại.