0
0
Lập trình
Sơn Tùng Lê
Sơn Tùng Lê103931498422911686980

Mẫu Thiết Kế Tạo Dựng trong Python: Builder và Prototype

Đăng vào 8 tháng trước

• 9 phút đọc

Giới thiệu

Trong bài viết trước, chúng ta đã khám phá một số mẫu thiết kế như Singleton, Factory và Abstract Factory. Hôm nay, chúng ta sẽ tiếp tục với hai mẫu thiết kế còn lại: Builder và Prototype. Những mẫu thiết kế này không chỉ giúp cải thiện cấu trúc của mã nguồn mà còn tối ưu hóa quy trình phát triển phần mềm.

Mẫu Builder

Định nghĩa

Mẫu Builder xây dựng các đối tượng phức tạp từng bước một, cho phép bạn tạo ra các biểu diễn khác nhau bằng cách sử dụng cùng một quy trình xây dựng. Mẫu này rất hữu ích khi bạn cần tạo ra các đối tượng với nhiều tham số tùy chọn mà không muốn tạo ra quá nhiều constructor.

Ví dụ Thực Tế

Dưới đây là ví dụ về cách sử dụng mẫu Builder để tạo ra một yêu cầu API trong Python:

python Copy
import requests

class APIRequest:
    def __init__(self):
        self.method = "GET"
        self.url = ""
        self.headers = {}
        self.params = {}
        self.json = None

    def __str__(self):
        return (
            f"{self.method} {self.url}\n"
            f"Headers: {self.headers}\n"
            f"Params: {self.params}\n"
            f"Body: {self.json}"
        )

class APIRequestBuilder:
    def __init__(self):
        self.request = APIRequest()

    def set_method(self, method: str):
        self.request.method = method.upper()
        return self

    def set_url(self, url: str):
        self.request.url = url
        return self

    def add_header(self, key: str, value: str):
        self.request.headers[key] = value
        return self

    def add_query_param(self, key: str, value: str):
        self.request.params[key] = value
        return self

    def set_json_body(self, data: dict):
        self.request.json = data
        return self

    def build(self):
        return self.request

    def send(self):
        print("Gửi yêu cầu:")
        print(self.request)
        print("-" * 50)
        response = requests.request(
            method=self.request.method,
            url=self.request.url,
            headers=self.request.headers,
            params=self.request.params,
            json=self.request.json
        )
        return response

class GitHubRequestDirector:
    def __init__(self, builder: APIRequestBuilder):
        self.builder = builder

    def get_user_repos(self, username):
        return (
            self.builder.set_method("GET")
                        .set_url(f"https://api.github.com/users/{username}/repos")
                        .add_header("Accept", "application/vnd.github.v3+json")
                        .build()
        )

if __name__ == "__main__":
    # Ví dụ 1: POST đến JSONPlaceholder
    post_builder = APIRequestBuilder()

    response = (
        post_builder.set_method("POST")
                    .set_url("https://jsonplaceholder.typicode.com/posts")
                    .add_header("Content-Type", "application/json")
                    .set_json_body({
                        "title": "Builder Pattern",
                        "body": "Làm cho việc gọi API trở nên dễ dàng hơn",
                        "userId": 42
                    })
                    .send()
    )

    print("Trạng thái:", response.status_code)
    print("Phản hồi JSON:", response.json())
    print("=" * 80)

    # Ví dụ 2: GET các repo trên GitHub sử dụng director
    github_builder = APIRequestBuilder()
    director = GitHubRequestDirector(github_builder)
    github_request = director.get_user_repos("octocat")

    response = requests.request(
        method=github_request.method,
        url=github_request.url,
        headers=github_request.headers
    )

    print("Các repo GitHub cho octocat:")
    for repo in response.json()[:3]:  # chỉ hiển thị 3 repo đầu tiên
        print("-", repo["name"])

Các Tình Huống Sử Dụng

  • Trình tạo truy vấn SQL
  • Trình tạo cấu hình
  • Trình tạo tài liệu (PDF, HTML)
  • Tạo nhân vật trong game
  • Trình tạo yêu cầu API

Mẫu Prototype

Định nghĩa

Mẫu Prototype tạo ra các đối tượng bằng cách sao chép các thể hiện hiện có thay vì tạo mới từ đầu. Mẫu này rất hữu ích khi việc tạo đối tượng tốn kém và bạn cần tạo ra nhiều đối tượng tương tự từ một mẫu.

Ví dụ Thực Tế

Dưới đây là ví dụ về cách sử dụng mẫu Prototype để gửi yêu cầu API:

python Copy
import copy
import requests

class Prototype:
    def clone(self):
        return copy.deepcopy(self)

class APIRequest(Prototype):
    def __init__(self, method="GET", url="", headers=None, params=None, json=None):
        self.method = method
        self.url = url
        self.headers = headers or {}
        self.params = params or {}
        self.json = json

    def send(self):
        print(f"Gửi yêu cầu {self.method} đến {self.url}")
        response = requests.request(
            method=self.method,
            url=self.url,
            headers=self.headers,
            params=self.params,
            json=self.json
        )
        return response

    def __str__(self):
        return (
            f"{self.method} {self.url}\n"
            f"Headers: {self.headers}\n"
            f"Params: {self.params}\n"
            f"Body: {self.json}"
        )

if __name__ == "__main__":
    # Bước 1: Tạo mẫu cho yêu cầu POST
    post_template = APIRequest(
        method="POST",
        url="https://jsonplaceholder.typicode.com/posts",
        headers={"Content-Type": "application/json"},
        json={"userId": 1}
    )

    # Bước 2: Sao chép mẫu và tùy chỉnh từng yêu cầu
    post1 = post_template.clone()
    post1.json["title"] = "Bài viết 1"
    post1.json["body"] = "Nội dung cho bài viết 1"

    post2 = post_template.clone()
    post2.json["title"] = "Bài viết 2"
    post2.json["body"] = "Nội dung cho bài viết 2"

    # Bước 3: Gửi yêu cầu
    for post in [post1, post2]:
        print("=" * 40)
        print("Yêu cầu:")
        print(post)
        print("-" * 40)
        response = post.send()
        print("Trạng thái:", response.status_code)
        print("Phản hồi:", response.json())

Các Tình Huống Sử Dụng

  • Mẫu tài liệu
  • Tạo đối tượng trong game
  • Mẫu cấu hình
  • Mẫu thành phần giao diện người dùng
  • Tạo dữ liệu thử nghiệm

Khi Nào Sử Dụng Mỗi Mẫu

  • Builder: Khi xây dựng các đối tượng phức tạp với nhiều tham số tùy chọn, hoặc khi quy trình xây dựng cần cho phép các biểu diễn khác nhau.
  • Prototype: Khi việc tạo đối tượng đắt đỏ và bạn có các đối tượng tương tự, hoặc khi bạn cần tạo các đối tượng dựa trên mẫu.

Lưu Ý Khi Sử Dụng

  • Mẫu Builder: Giúp quản lý cấu trúc mã tốt hơn, nhưng có thể phức tạp hơn khi chỉ cần một đối tượng đơn giản.
  • Mẫu Prototype: Giúp tiết kiệm tài nguyên nhưng cần cẩn thận với việc sao chép để đảm bảo không tạo ra sai lệch dữ liệu.

Hỏi Đáp

Mẫu thiết kế nào tốt hơn khi tôi cần tạo nhiều đối tượng tương tự?

Mẫu Prototype sẽ là lựa chọn tốt hơn khi bạn cần tạo nhiều đối tượng tương tự vì nó giúp tiết kiệm tài nguyên.

Có nên sử dụng mẫu Builder cho các đối tượng đơn giản không?

Nếu đối tượng của bạn đơn giản và không có nhiều tham số, việc sử dụng mẫu Builder có thể là quá mức cần thiết.

Kết luận

Mẫu thiết kế Builder và Prototype đều là những công cụ mạnh mẽ trong lập trình Python, giúp bạn xây dựng mã nguồn dễ bảo trì và mở rộng. Hãy thử nghiệm và áp dụng chúng trong các dự án của bạn để nâng cao hiệu quả phát triển phần mềm. Đừng ngần ngại chia sẻ ý kiến và phê bình bài viết này để chúng ta cùng nhau học hỏi và phát triển!

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào