Nội dung
Mục tiêu
Builder là một mẫu thiết kế sáng tạo cho phép bạn xây dựng các đối tượng phức tạp theo từng bước. Mẫu cho phép bạn tạo ra các kiểu và mô tả khác nhau của một đối tượng bằng cách sử dụng cùng một mã khởi tạo.
Đặt vấn đề
Hãy tưởng tượng có một đối tượng phức tạp đòi hỏi nhiều công sức, từng bước khởi tạo nhiều trường và các đối tượng lồng nhau. Mã khởi tạo như vậy thường được nhét bên trong một hàm tạo khổng lồ với rất nhiều tham số. Hoặc thậm chí tệ hơn, nằm rải rác trên toàn bộ mã client.
Hãy thử nghĩ về cách tạo đối tượng House
. Để xây một ngôi nhà đơn giản, bạn cần xây dựng bốn bức tường và sàn nhà, lắp cửa ra vào, một cặp cửa sổ và xây dựng mái nhà. Nhưng nếu bạn muốn một ngôi nhà lớn hơn, sáng sủa hơn, có sân sau và các tiện ích khác (như hệ thống sưởi, hệ thống ống nước và hệ thống dây điện) thì sao?
Giải pháp đơn giản nhất là mở rộng lớp House
cơ sở và tạo một tập hợp các lớp con để bao gồm tất cả các kết hợp của các tham số. Nhưng cuối cùng bạn sẽ xoắn não với một lượng đáng kể các lớp con. Bất kỳ thông số mới nào, chẳng hạn như kiểu hiên nhà, sẽ yêu cầu phát triển hệ thống phân cấp này nhiều hơn nữa.
Một cách tiếp cận khác không liên quan đến việc tạo các lớp con. Bạn có thể viết một hàm tạo khổng lồ ngay trong lớp House
cơ sở với tất cả các tham số có thể có để điều khiển đối tượng house. Trong khi cách tiếp cận này thực sự loại bỏ sự cần thiết của các lớp con nhưng lại tạo ra một vấn đề khác.
Trong hầu hết các trường hợp, phần lớn các tham số sẽ không được sử dụng, làm cho các cuộc gọi hàm tạo khá xấu. Ví dụ, chỉ một phần nhỏ các ngôi nhà có bể bơi, vì vậy các thông số liên quan đến bể bơi sẽ vô dụng chín trên mười lần.
Giải pháp
Mẫu Builder gợi ý rằng bạn nên trích xuất mã xây dựng đối tượng ra khỏi lớp của chính nó và di chuyển nó đến các đối tượng riêng biệt được gọi là các builder.
Mẫu sẽ sắp xếp việc xây dựng đối tượng thành một tập hợp các bước (buildWalls
, buildDoor
, v.v.). Để tạo một đối tượng, bạn thực hiện một loạt các bước này trên một đối tượng builder. Quan trọng là bạn không cần phải gọi tất cả các bước. Bạn có thể gọi những bước cần thiết để tạo ra một cấu hình cụ thể của một đối tượng.
Một số bước xây dựng có thể yêu cầu thực hiện khác nhau khi bạn cần xây dựng các mô tả khác nhau của sản phẩm. Ví dụ, tường của một nhà tranh có thể được xây bằng gỗ, nhưng tường lâu đài phải được xây bằng đá.
Trong trường hợp này, bạn có thể tạo một số lớp builder khác nhau triển khai cùng một tập hợp các bước xây dựng, nhưng theo một cách khác. Sau đó, bạn có thể sử dụng các builder này trong quá trình xây dựng (tức là một tập hợp lệnh gọi đến các bước xây dựng) để tạo ra các kiểu đối tượng khác nhau.
Chẳng hạn, một builder xây dựng mọi thứ từ gỗ và thủy tinh, cái thứ hai xây dựng mọi thứ bằng đá và sắt và cái thứ ba sử dụng vàng và kim cương. Bằng cách gọi cùng một nhóm các bước, bạn sẽ có được một ngôi nhà bình thường từ builder đầu tiên, một lâu đài nhỏ từ cái thứ hai và một cung điện từ cái thứ ba. Tuy nhiên, điều này sẽ chỉ hoạt động nếu mã client gọi các bước xây dựng có thể tương tác với các builder thông qua giao diện chung.
Director
Bạn có thể trích xuất một loạt lệnh gọi đến các bước của builder mà bạn sử dụng để xây dựng một sản phẩm thành một lớp riêng biệt có tên là Director. Lớp này xác định thứ tự thực hiện các bước xây dựng, trong khi builder cung cấp việc triển khai cho các bước đó.
Không cần thiết phải có lớp Director trong chương trình của bạn. Bạn luôn có thể gọi các bước xây dựng theo thứ tự cụ thể trực tiếp từ mã client. Tuy nhiên, lớp Director có thể là một nơi tốt để đưa các quy trình xây dựng khác nhau để bạn có thể sử dụng lại chúng trong chương trình của mình.
Ngoài ra, lớp Director hoàn toàn giấu kín các chi tiết cấu tạo sản phẩm với mã client. Client chỉ cần liên kết builder với director, khởi chạy các lệnh xây dựng với director và nhận kết quả từ builder.
Cấu trúc
- Giao diện Builder khai báo các bước xây dựng sản phẩm chung cho tất cả các loại builder.
- Các Concrete Builder cung cấp các cách triển khai khác nhau của các bước xây dựng. Các concrete builder có thể tạo ra các sản phẩm không tuân theo giao diện chung.
- Product là đối tượng kết quả. Các sản phẩm do các builder khác nhau tạo ra không nhất thiết phải thuộc cùng một hệ thống phân cấp hoặc giao diện lớp.
- Lớp Director xác định thứ tự gọi các bước xây dựng, vì vậy bạn có thể tạo và sử dụng lại các cấu hình cụ thể của sản phẩm.
- Client phải liên kết một trong các đối tượng builder với director. Thông thường, nó chỉ được thực hiện một lần, thông qua các tham số của hàm tạo của director. Sau đó, director sử dụng đối tượng builder đó cho tất cả các xây dựng tiếp theo. Tuy nhiên, có một cách tiếp cận khác là client truyền đối tượng builder sang hàm thành viên của director. Trong trường hợp này, bạn có thể sử dụng một builder khác mỗi khi bạn tạo cái gì đó với director.
Khả năng áp dụng
- Sử dụng mẫu Builder để loại bỏ “hàm tạo kính thiên văn” (hàm tạo với nhiều tham số).
- Sử dụng mẫu Builder khi bạn muốn chương trình của mình có thể tạo các mô tả khác nhau của một số sản phẩm (ví dụ, nhà bằng đá và bằng gỗ).
- Sử dụng Builder để tạo cây Composite hoặc các đối tượng phức tạp khác.
Ưu và nhược điểm
😄😄😄
Bạn có thể xây dựng các đối tượng theo từng bước, trì hoãn các bước xây dựng hoặc chạy các bước một cách đệ quy.
Bạn có thể sử dụng lại cùng một mã xây dựng khi xây dựng các mô tả khác nhau của sản phẩm.
Nguyên tắc Đơn Trách nhiệm. Bạn có thể tách mã xây dựng phức tạp khỏi logic của sản phẩm.
🙁🙁🙁
Độ phức tạp tổng thể của mã tăng lên vì mẫu yêu cầu tạo nhiều lớp mới.
Mối quan hệ với các mẫu khác
- Nhiều thiết kế bắt đầu bằng cách sử dụng Factory Method (ít phức tạp hơn và có thể tùy chỉnh nhiều hơn qua các lớp con) và phát triển theo hướng Abstract Factory, Prototype hoặc Builder (linh hoạt hơn nhưng phức tạp hơn).
- Builder tập trung vào việc xây dựng các đối tượng phức tạp theo từng bước. Abstract Factory chuyên tạo các họ đối tượng liên quan. Abstract Factory trả lại sản phẩm ngay lập tức, trong khi Builder cho phép bạn chạy một số bước xây dựng bổ sung trước khi đưa ra sản phẩm.
- Bạn có thể sử dụng Builder khi tạo các cây Composite phức tạp vì bạn có thể lập trình các bước xây dựng của nó để hoạt động đệ quy.
- Bạn có thể kết hợp Builder với Bridge: lớp director đóng vai trò trừu tượng, trong khi các builder khác nhau đóng vai trò triển khai.
- Abstract Factory, Builder và Prototype đều có thể được triển khai dưới dạng các Singleton.
Để lại một bình luận