1.6. Prototype

1.6.1. تعریف

الگوی طراحی Prototype، یک الگوی سازنده یا creational محسوب میشه که به شما اجازه میده از آبجکت های موجود کپی ایجاد کنید بدون اینکه سطوح بالای برنامه رو درگیر جزئیات فرآیند کپی بکنید.

در واقع قراره به جای اینکه آبجکت های جدید رو از روش معمول استفاده از کلمه کلیدی new ایجاد کنیم و بعد تک تک property ها و method ها رو منتقل کنیم به آبجکت جدید، از روش بهتری استفاده کنیم!

1.6.2. اجزاء

الگوی طراحی Prototype از چند بخش اصلی تشکیل میشه:

1. Prototype interface/abstract class: مشخص کننده متدهای معمول که توسط concrete ها باید پیاده سازی بشن. (شامل متد clone که مسئول ایجاد کپی از آبجکت مورد نظر هست)

  1. Concrete prototypes: مشخص کننده ساختار و فرآیند دقیق کپی شدن آبجکت.

3. Client: بخشی از کد که از Prototype ها برای ایجاد کپی استفاده می کنه. در واقع کارش اینه که از Prototype Manager یک Prototype دریافت می کنه و از اون برای ایجاد کپی آبجکت مورد نظر استفاده می کنه.

  1. Prototype manager: یک بخش اختیاری که مسئولیتش مدیریت Prototype های مختلف و تحویل دادن Prototype مناسب هست.

UML of Prototype Design Pattern

User:Giacomo Ritucci, CC BY-SA 3.0, via Wikimedia Commons

1.6.3. چه زمانی استفاده میشه؟

این الگو رو زمانی استفاده می کنیم که از یک آبجکت تعدادی کپی نیاز داریم و میدونیم که فرآیند نسبتا پیچیده ای برای انجام این کپی و انتقال property و method ها نیاز هست.

با استفاده از این الگو این پیچیدگی رو از بدنه ی کد مربوط به قسمت های سطح بالای برنامه جدا می کنیم.

Caution

✅ مزایای استفاده

*. جداسازی فرآیند کپی آبجکت از منطق برنامه

*. ایجاد ساده تر آبجکت های جدید

*. جلوگیری از نوشته شدن کدهای زیاد تکرارشونده برای ایجاد اشیاء

Warning

❌ معایب استفاده

کپی کردن آبجکت های شامل مرجع های circular ممکنه باعث بروز خطا بشه

1.6.4. کاربرد عملی

فرض کنید برنامه ای داریم که یک سری کتاب رو تولید می کنه و این کتاب ها میتونن عناوین متنوعی داشته باشن.

چکار کنیم که مجبور نباشیم برای هر کتاب از ابتدا یک آبجکت جدید ایجاد کنیم؟

1.6.5. پیاده سازی

ابتدا ساختار کلی Prototype رو مشخص می کنیم:

 1<?php
 2
 3abstract class BookPrototype
 4{
 5    protected string $title;
 6    protected string $topic;
 7
 8    abstract function __clone();
 9
10    function getTitle(): string
11    {
12        return $this->title;
13    }
14
15    function setTitle($titleIn): void
16    {
17        $this->title = $titleIn;
18    }
19
20    function getTopic(): string
21    {
22        return $this->topic;
23    }
24}

حالا دو پیاده سازی مختلف برای این Prototype در نظر میگیریم:

 1<?php
 2
 3class PHPBookPrototype extends BookPrototype {
 4    function __construct() {
 5        $this->topic = 'PHP';
 6    }
 7    function __clone() {
 8    }
 9}
10
11class SQLBookPrototype extends BookPrototype {
12    function __construct() {
13        $this->topic = 'SQL';
14    }
15    function __clone() {
16    }
17}

1.6.6. نحوه فراخوانی

 1<?php
 2
 3writeln('BEGIN TESTING PROTOTYPE PATTERN');
 4writeln('');
 5
 6$phpProto = new PHPBookPrototype();
 7$sqlProto = new SQLBookPrototype();
 8
 9$book1 = clone $sqlProto;
10$book1->setTitle('SQL For Cats');
11writeln('Book 1 topic: ' . $book1->getTopic());
12writeln('Book 1 title: ' . $book1->getTitle());
13writeln('');
14
15$book2 = clone $phpProto;
16$book2->setTitle('OReilly Learning PHP 5');
17writeln('Book 2 topic: ' . $book2->getTopic());
18writeln('Book 2 title: ' . $book2->getTitle());
19writeln('');
20
21$book3 = clone $sqlProto;
22$book3->setTitle('OReilly Learning SQL');
23writeln('Book 3 topic: ' . $book3->getTopic());
24writeln('Book 3 title: ' . $book3->getTitle());
25writeln('');
26
27writeln('END TESTING PROTOTYPE PATTERN');
28
29function writeln($line_in): void
30{
31    echo $line_in . "<br/>";
32}
33
34// OUTPUT:
35// BEGIN TESTING PROTOTYPE PATTERN
36//
37// Book 1 topic: SQL
38// Book 1 title: SQL For Cats
39//
40// Book 2 topic: PHP
41// Book 2 title: OReilly Learning PHP 5
42//
43// Book 3 topic: SQL
44// Book 3 title: OReilly Learning SQL
45//
46// END TESTING PROTOTYPE PATTERN

و تمام!