1.5. Builder¶
1.5.1. تعریف¶
الگوی طراحی Builder، یک الگوی سازنده یا creational هست که به ما اجازه میده آبجکت هایی که فرآیند ایجاد پیچیده ای دارن رو به صورت مرحله به مرحله تولید کنیم، بدون اینکه این پیچیدگی در سطوح بالاتر برنامه دیده بشه.
1.5.2. اجزاء¶
الگوی طراحی Builder از چند بخش اصلی تشکیل میشه:
1. Director: مسئول مدیریت فرآیند خلق آبجکت هست و ارتباط مستقیمی با Builder برقرار می کنه تا مطمئن بشه محصول (آبجکت) نهایی همون چیزی هست که خواسته شده.
Builder: یک interface برای خلق اجزاء آبجکت پیچیده ی نهایی که شامل متدهای ایجاد هر بخش از محصول نهایی هست.
Concrete Builder: کلاس هایی که Builder رو پیاده سازی می کنن و مراحل خلق آبجکت نهایی رو مشخص می کنن.
Product: آبجکت مورد نظر که قراره بعد از گذر از مراحل مشخص شده در ترکیبی از اجزای مختلف خلق بشه.
4. Client: بخشی که با ارتباط دادن موارد قبل، ساخت آبجکت از Builder، ارسال اون به Director و فراخوانی متد build منجر به خلق آبجکت نهایی میشه.
Vanderjoe, CC BY-SA 4.0, via Wikimedia Commons
1.5.3. چه زمانی استفاده میشه؟¶
این الگو زمانی استفاده میشه که خلق آبجکت نهایی مراحل پیچیده ای داشته باشه و شامل چندین قدم باشه و نیاز داریم روی تمام مراحل کنترل داشته باشیم.
این الگو همچنین به ما اجازه میده نمایش های مختلفی از یک آبجکت داشته باشیم بدون اینکه نیاز باشه سطوح پایین پیاده سازی رو ویرایش یا modify کنیم. (Open/Closed Principle)
مثلا اگر Builder ما خلق یک خانه هست، این نمایش های مختلف میتونه خانه سنگی، چوبی، آجری و… باشه که متفاوت هستن اما مراحل خلق مشابهی دارن.
Caution
✅ مزایای استفاده
*. با استفاده از این الگو امکان خلق قدم به قدم آبجکت های پیچیده فراهم میشه
*. استفاده مجدد از مراحل مشابه خلق برای نمایش های مختلف
*. رعایت اصل Single Responsibility با جداسازی مراحل خلق پیچیده ی آبجکت از ساختار اصلی کد و بخش منطق برنامه
Warning
❌ معایب استفاده
پیچیده تر شدن برنامه به علت نیاز به تعریف انواع interface و concrete در برنامه
1.5.4. کاربرد عملی¶
فرض کنید محصول نهایی ما یک برگر هست که خروجی نهایی میتونه یک برگر ساده یا یک برگر ویژه باشه!
برای این کار مراحل در هر دو نوع برگر به یک شکل هست اما مراحل تولید برگر پیچیده هست پس اینجا از الگوی طراحی Builder کمک میگیریم.
1.5.5. پیاده سازی¶
ابتدا ساختار کلی Builder رو به این صورت تعریف می کنیم:
1<?php
2
3// Builder interface
4interface BurgerBuilder {
5 public function addBun();
6 public function addPatty();
7 public function addCheese();
8 public function addToppings();
9 public function getBurger(): Burger;
10}
حالا دو پیاده سازی مختلف برای برگر معمولی و برگر ویژه داریم:
1<?php
2
3// Concrete builder for basic burger
4class BasicBurgerBuilder implements BurgerBuilder {
5 private Burger $burger;
6
7 public function __construct() {
8 $this->burger = new Burger();
9 }
10
11 public function addBun() {
12 $this->burger->setBun("Plain Bun");
13 }
14
15 public function addPatty() {
16 $this->burger->setPatty("Beef Patty");
17 }
18
19 public function addCheese() {
20 $this->burger->setCheese("American Cheese");
21 }
22
23 public function addToppings() {
24 // No additional toppings for basic burger
25 }
26
27 public function getBurger(): Burger {
28 return $this->burger;
29 }
30}
31
32// Concrete builder for deluxe burger
33class DeluxeBurgerBuilder implements BurgerBuilder {
34 private Burger $burger;
35
36 public function __construct() {
37 $this->burger = new Burger();
38 }
39
40 public function addBun() {
41 $this->burger->setBun("Sesame Seed Bun");
42 }
43
44 public function addPatty() {
45 $this->burger->setPatty("Beef Patty");
46 }
47
48 public function addCheese() {
49 $this->burger->setCheese("Swiss Cheese");
50 }
51
52 public function addToppings() {
53 $this->burger->addTopping("Lettuce")
54 ->addTopping("Tomato")
55 ->addTopping("Onion")
56 ->addTopping("Pickles")
57 ->addTopping("Ketchup")
58 ->addTopping("Mustard");
59 }
60
61 public function getBurger(): Burger {
62 return $this->burger;
63 }
64}
و Director که مسئول خلق آبجکت هست:
1<?php
2
3// Director
4class BurgerDirector {
5 private BurgerBuilder $builder;
6
7 public function setBuilder(BurgerBuilder $builder): Burger {
8 $this->builder = $builder;
9 }
10
11 public function buildBurger(): Burger {
12 $this->builder->addBun();
13 $this->builder->addPatty();
14 $this->builder->addCheese();
15 $this->builder->addToppings();
16
17 return $this->builder->getBurger();
18 }
19}
حالا بخش Product رو تعریف می کنیم که میشه آبجکت نهایی که باید برگرده:
1<?php
2
3// Product
4class Burger {
5 private string $bun;
6 private string $patty;
7 private string $cheese;
8 private array $toppings;
9
10 public function setBun(string $bun): void
11 {
12 $this->bun = $bun;
13 }
14
15 public function setPatty(string $patty): void
16 {
17 $this->patty = $patty;
18 }
19
20 public function setCheese(string $cheese): void
21 {
22 $this->cheese = $cheese;
23 }
24
25 public function addTopping(string $topping): static
26 {
27 $this->toppings[] = $topping;
28 return $this;
29 }
30
31 public function getBurgerInfo(): string {
32 $toppingsStr = implode(", ", $this->toppings);
33 return "Burger: {$this->bun} + {$this->patty} + {$this->cheese} + {$toppingsStr}";
34 }
35}
و در نهایت هم Client رو داریم:
1<?php
2
3// Client code
4function clientCode(): void
5{
6 // Create a new director
7 $director = new BurgerDirector();
8
9 // Create a basic burger builder
10 $basicBuilder = new BasicBurgerBuilder();
11
12 // Set the builder for the director
13 $director->setBuilder($basicBuilder);
14
15 // Build the burger
16 $basicBurger = $director->buildBurger();
17
18 // Print the burger
19 echo $basicBurger->getBurgerInfo();
20}
1.5.6. نحوه فراخوانی¶
1clientCode();
به همین زیبایی!