3.9. Template Method

3.9.1. تعریف

دیزاین پترن Template Method یک الگوی رفتاری محسوب میشه که اسکلت و ساختار الگوریتم رو در سوپرکلاس تعریف می کنه اما به زیر کلاس ها اجازه میده بدون تغییر در ساختار الگوریتم، بخش هایی از الگوریتم رو تغییر بدن یا override کنن.

شما در فرآیند طراحی برنامه یک سری step ها رو مشخص می کنید تا در نهایت الگوریتم شما به نتیجه برسه، این قدم ها رو به عنوان یک الگوی کلی در کلاس والد مشخص می کنید و اون ها رو به صورت متد های abstract، یا با یک پیاده سازی پیشفرض مشخص می کنید و به زیرکلاس ها اجازه میدید هر کدوم قدم ها رو به شکل مورد نظر پیاده سازی کنن.

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

این الگو معمولا زیاد استفاده میشه و احتمالا باهاش مواجه هم شدید.

از این الگو زمانی استفاده میشه که قصد داریم به زیرکلاس ها اجازه بدیم قدم های مشخصی از الگوریتم کلی رو به صورت دلخواه پیاده سازی کنن.

این الگو زمانی در برنامه به کار میره که کلاس های زیادی در برنامه با الگوریتم تقریبا مشابه داریم که فقط بخش های خاصی از اون ها با هم تفاوت داره.

3.9.3. اجزاء

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

بخش اول این الگو کلاس پایه ی Abstract هست که الگوریتم کلی رو مشخص می کنه و یک ساختار کلی برای زیرکلاس ها تعیین می کنه.

بخش بعد زیرکلاس ها هستن که تعاریف خودشون از الگوریتم کلی رو تعریف می کنن. البته در قسمت هایی که این اجازه بهشون داده میشه.

و در نهایت هم Client رو داریم که از این دیزاین پترن استفاده می کنه.

UML of Template Method Design Pattern

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

Caution

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

اجازه تغییر و override بخش های مشخصی از سوپرکلاس به زیرکلاس ها

Warning

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

ممکن است با تعریف interface نامناسب، اصل Liskov Substitution نقض بشه

هر چقدر step های الگوریتم اصلی بیشتر باشه، نگهداری برنامه و الگو سخت تر خواهد شد

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

کاربرد این دیزاین پترن رو معمولا در PHP به کرات میبینیم.

یکی از معمول ترین مواردی که استفاده از این الگو دیده میشه، گسترش و override کردن رفتارهای پیشفرض فریمورک با ارث بری هست.

در یک مثال عملی فرض کنید قصد داریم یک سیستم ناتیفیکیشن ایمیل رو پیاده سازی کنیم که برای کاربرد های مختلف متن و عنوان متفاوتی داره.

3.9.5. پیاده سازی

ساختار کلاس Abstract و پایه ما به این صورت هست:

 1<?php
 2
 3abstract class EmailSender
 4{
 5    protected string $recipient;
 6
 7    public function __construct(string $recipient)
 8    {
 9        $this->recipient = $recipient;
10    }
11
12    public function sendEmail(): void
13    {
14        $subject = $this->getSubject();
15        $body = $this->getBody();
16
17        // Code to send email with subject and body to $this->recipient
18    }
19
20    protected abstract function getSubject(): string;
21
22    protected abstract function getBody(): string;
23}

و بعد هم زیرکلاس ها رو به این صورت داریم:

 1<?php
 2
 3class WelcomeEmailSender extends EmailSender
 4{
 5    protected function getSubject(): string
 6    {
 7        return 'Welcome to our site!';
 8    }
 9
10    protected function getBody(): string
11    {
12        return 'Thank you for joining our site!';
13    }
14}
15
16class UpdateEmailSender extends EmailSender
17{
18    protected function getSubject(): string
19    {
20        return 'Your account details have been updated';
21    }
22
23    protected function getBody(): string
24    {
25        return 'Your account details have been updated. Please log in to view your updated information.';
26    }
27}

که میشه دو نوع مختلف ایمیل با متن و عنوان متفاوت

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

1<?php
2
3$welcomeEmailSender = new WelcomeEmailSender('salpars2004@gmail.com');
4$welcomeEmailSender->sendEmail();
5
6$updateEmailSender = new UpdateEmailSender('salpars2004@yahoo.com');
7$updateEmailSender->sendEmail();

به همین سادگی!