Creational patterns

Nếu ai đã từng làm việc với những ngôn ngữ hướng đối tượng, chắc chắn ai cũng đã từng nghe qua khái niệm về Design patterns. Là các giải pháp đã được tối ưu, được tái sử dụng cho các vấn đề lập trình mà chúng ta phải gặp hằng ngày; là một khuôn mẫu đã được suy nghĩ, giải quyết trong tình huống cụ thể. Hôm nay mình xin giới thiệu về Creational Pattern (nhóm khởi tạo), là một trong ba mẫu về Design patterns. Trong kỹ thuật phần mềm, các mẫu thiết kế creational là các mẫu thiết kế đối ứng với các cơ chế tạo đối tượng, cố gắng tạo các đối tượng theo cách phù hợp với từng tình huống. Các hình thức cơ bản của việc tạo đối tượng là kết quả của các vấn đề thiết kế hoặc sự phức tạp trong vấn đề thiết kế. Các mẫu thiết kế creational giải quyết vấn đề này bằng cách kiểm soát việc tạo các đối tượng. Mẫu thiết kế bao gồm : * Abstract Factory * Builder * Factory Method * Object Pool * Prototype * Singleton

1. Abstract Factory

  • Mục đích: * Cung cấp giao diện cho việc tạo ra các mẫu chung của các đội tượng liên quan hoặc phụ thuộc mà không nêu rõ các lớp cụ thể của chúng. * Là một hệ thống phân cấp đóng gói: nhiều "nền tảng", và xây dựng một bộ "sản phẩm". * Với mô hình này, thì toán tử new được xem là không tốt.
  • Bài toán đặt ra: Nếu một ứng dụng của bạn là linh động trong việc thay đổi, các phụ thuộc nền tảng cần được đóng gói. Những "nền tảng" này có thể bao gồm: hệ thống giao diện, hệ điều hành, cơ sở dữ liệu.... Thông thường, sự đóng gói này không được thiết kế trước, và cần rất nhiều case if với các tùy chọn cho tất cả các nền tảng hiện đang được hỗ trợ được sinh ra trong suốt quá trình xây dựng mã.
  • Hướng giải quyết: Cung cấp mức độ gián tiếp sự trừu tượng việc tạo ra các đối tượng chung hoặc phụ thuộc mà không trực tiếp xác định lớp cụ thể của chúng. Đối tượng "factory" có trách nhiệm cung cấp tạo ra các dịch vụ cho toàn bộ nền tảng. Phía khách không trực tiếp tạo ra các đối tượng nền tảng, mà nó yêu cầu đối tượng nền tảng làm điều đó cho chúng. Sẽ có 1 lớp trừu tượng được tạo đại diện cho toàn bộ ứng dụng. và chỉ được khởi tạo 1 lần. Do các dịch vụ cung cấp bởi các đối tượng gốc như vậy là phổ biến, nó thường được thực hiện như một Singleton.

2. Factory method

  • Mục đích: * Định nghĩa giao diện cho việc tạo đối tượng, nhưng để các lớp con quyết định lớp được thể hiện. Factory method cho phép một lớp được triển khai sự thể hiện thành các lớp con. * Xác định một constructor ảo. * Phương thức new được coi là không cần thiết.
  • Bài toán đặt ra: Một khuôn mẫu cần chuẩn hóa mô hình kiến trúc cho một loạt các ứng dụng, nhưng cho phép các ứng dụng cá nhân xác định các đối tượng riêng của mình và cung cấp sự khởi tạo cho chúng.
  • Hướng giải quyết: Factory Method là phương pháp tạo ra các đối tượng như là các phương thức mẫu dùng để cài đặt thuật toán. Một lớp cha xác định tất cả các hành vi chuẩn và chung, sau đó ủy thác việc xây dựng chi tiết ở các lớp con. Mọi người thường sử dụng Factory Method như một cách chuẩn để tạo ra đối tượng, nhưng không cần thiết nếu: lớp được khởi tạo không bao giờ thay đổi, hoặc sự khởi tạo diễn ra trong một thao tác mà các lớp con có thể dễ dàng ghi đè. Factory Method tương tự như Abstract Factory nhưng không bao gồm the emphasis on families. Factory Method thường được sử dụng để xác định khung của một bản mẫu, và sau đó được thực hiện bởi người sử dụng bản mẫu.

3. Ví dụ

Do sự tương đồng của 2 mẫu design pattern này nên mình xin phép trình bày 1 ví dụ đơn giản sau: Bài toán: Tạo tài liệu theo các định dạng PDF, XML, WORD... Với bài toán này, không ít người sử dụng câu lệnh condition if else để thực hiện việc xuất dữ liệu theo type của từng định dạng. Nhưng qua việc tìm hiểu hai design patterns ở trên, việc giải quyết bài toán này thật đơn giản, và tránh được việc phải sửa code trong condition if else khi mà sếp bạn muốn xuất tài liệu ở dưới 1 định dạng nào khác nữa. Design pattern được sử dụng hầu hết trong các ngôn ngữ hướng đối tượng, nên mình xin phép không đi sâu vào việc xây dựng chi tiết code mà chỉ đi vào tổng quát về hướng giải quyết vấn đề.

  • Đầu tiên, mình có một lớp trừu tượng là DocumentFactory, với một phương thức export(), với từng lớp con khi extend class cha này, sẽ phải triển khai chi tiết phương thức export() này;
        class DocumentFactory
             def export
                 raise "You need implement in subclass"
             end
        end
    
  • Với mỗi kiểu document được xuất ra, mình thiết kế một class để có thể triển khai việc export() của lớp cha DocumentFactory, bao gồm 3 class là HTMLDocument, XMLDocument, PDFDocument. Sau này, khi muốn thêm một định dạng dữ liệu nào đó nữa, bạn chỉ cần tạo thêm 1 class tương ứng cho định dạng đó và triển khai hàm export() là xong"
       class HTMLDocument < DocumentFactory
             def export
                 # trả về dữ liệu dạng HTML
             end
        end
    
        class PDFDocument < DocumentFactory
             def export
                 # trả về dữ liệu dạng PDF
             end
        end
    
     class XMLDocument < DocumentFactory
           def export
                 # trả về dữ liệu dạng XML
           end
     end
    
  • Việc Report giờ chỉ phụ thuộc vào loại document mà bạn muốn sử dụng:
        class Report
           def getReport(Document document)
               document.export()
           end
       end
    
    Qua ví dụ trên, các bạn đã thấy sự tiện lợi của việc sử dụng Design pattern trong việc phát triển ứng dụng là lớn như thế nào ngay từ lúc phát triển cho đến bảo trì. Mình cũng mới tìm hiểu về các mẫu design nên còn nhiều sai sót. Cảm ơn các bạn đã bớt chút thời gian đọc bài viết của mình.!!!! Nguồn tài liệu: https://sourcemaking.com/design_patterns/creational_patterns