سی ام اس نویسسی ام اس نویسیاد بگیر، سیستم خودتو بنویس
مجلهتماس با ما
سی ام اس نویسسی ام اس نویس

CMS نویس مرجعی برای آموزش برنامه نویسی وب و PHP، توسعه افزونه‌های اختصاصی وردپرس، طراحی ورک‌فلو و اتوماسیون با n8n و توسعه CMS های اختصاصی است. هدف ما ارائه آموزش‌های کاربردی و راهکارهای حرفه‌ای برای توسعه‌دهندگان، کسب‌وکارها و علاقه‌مندان به دنیای برنامه‌نویسی است.

پیوندهای سریع
محصولات فیزیکیمحصولات دیجیتالدوره‌های آموزشی
سی ام اس نویس
مجله سی ام اس نویستماس با ماپنل کاربری
سی ام اس نویس — تمامی حقوق برای سی ام اس نویس محفوظ است. © 1406 تماس با ما09307711941
Bridge Pattern در PHP چیست؟ آموزش الگوی Bridge با مثال عملی

Bridge Pattern در PHP چیست؟ آموزش الگوی Bridge با مثال عملی

ممدیر کل سیستم ۲۵ شهریور ۱۴۰۵ ۱۷ دقیقه مطالعه ۱ بازدید
Bridge Pattern در PHP چیست؟ آموزش الگوی Bridge با مثال عملی

در پروژه‌های PHP و Laravel گاهی یک کلاس باید در چند بُعد مختلف توسعه پیدا کند.

برای مثال فرض کنید یک سیستم نمایش محتوا داریم که باید:

  • چند نوع صفحه داشته باشد؛
  • چند نوع خروجی تولید کند؛
  • از HTML و JSON پشتیبانی کند؛
  • در آینده خروجی XML یا Markdown نیز به آن اضافه شود.

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

مثلاً ممکن است کلاس‌هایی مانند این‌ها ایجاد شوند:


HtmlSimplePage

JsonSimplePage

HtmlProductPage

JsonProductPage

HtmlArticlePage

JsonArticlePage

با اضافه‌شدن هر نوع صفحه یا خروجی، باید کلاس‌های ترکیبی بیشتری ایجاد کنیم.

Bridge Pattern برای حل چنین مسئله‌ای طراحی شده است. این الگو یک ساختار بزرگ را به دو سلسله‌مراتب مستقل تقسیم می‌کند:

  1. Abstraction
  2. Implementation

در این روش، Abstraction به‌جای اینکه تمام جزئیات Implementation را در خود نگهداری کند، یک نمونه از Implementation را دریافت کرده و عملیات مربوط به آن را به این Object واگذار می‌کند. <Cite refs={["turn0search0","turn0search2"]} />


Bridge Pattern چیست؟

Bridge Pattern یک Structural Design Pattern است که به ما اجازه می‌دهد Abstraction را از Implementation جدا کنیم تا هرکدام بتوانند مستقل از دیگری توسعه پیدا کنند.

به زبان ساده:

> به‌جای ساختن کلاس‌های متعدد برای تمام ترکیب‌های ممکن، دو بخش مستقل ایجاد می‌کنیم و آن‌ها را از طریق Composition به یکدیگر متصل می‌کنیم.

ساختار کلی به این شکل است:


Abstraction

    |

    | has-a

    v

Implementation

برای مثال:


Page

    |

    v

Renderer

در این مثال:

  • Page مسئول منطق کلی صفحه است.
  • Renderer مسئول نحوه نمایش صفحه است.
  • HtmlRenderer خروجی HTML تولید می‌کند.
  • JsonRenderer خروجی JSON تولید می‌کند.

بنابراین می‌توانیم یک ProductPage را با HtmlRenderer یا JsonRenderer استفاده کنیم، بدون اینکه برای هر ترکیب کلاس جداگانه بسازیم.


مشکل اصلی که Bridge Pattern حل می‌کند

فرض کنید یک سیستم پرداخت داریم.

در این سیستم دو بُعد مستقل وجود دارد:

نوع پرداخت

  • پرداخت عادی
  • پرداخت اشتراکی
  • پرداخت اقساطی

درگاه پرداخت

  • زرین‌پال
  • Stripe
  • PayPal

اگر این دو بُعد را با Inheritance ترکیب کنیم، احتمالاً کلاس‌هایی مانند زیر خواهیم داشت:


NormalZarinpalPayment

NormalStripePayment

NormalPaypalPayment



SubscriptionZarinpalPayment

SubscriptionStripePayment

SubscriptionPaypalPayment



InstallmentZarinpalPayment

InstallmentStripePayment

InstallmentPaypalPayment

در این حالت، با اضافه‌شدن نوع جدید پرداخت یا درگاه جدید، تعداد کلاس‌ها بیشتر می‌شود.

این مشکل را می‌توان با Bridge Pattern حل کرد.

به‌جای ساخت کلاس‌های ترکیبی، دو سلسله‌مراتب مستقل می‌سازیم:


Payment

    ├── NormalPayment

    ├── SubscriptionPayment

    └── InstallmentPayment



PaymentGateway

    ├── ZarinpalGateway

    ├── StripeGateway

    └── PaypalGateway

سپس هر نوع Payment به یک PaymentGateway متصل می‌شود.


مفهوم Abstraction در Bridge Pattern

Abstraction بخش سطح بالای سیستم است.

این بخش معمولاً منطق اصلی و قابل‌فهم برای Client را در اختیار قرار می‌دهد.

برای مثال:


abstract class Payment

{

    public function __construct(

        protected PaymentGateway $gateway

    ) {

    }



    abstract public function pay(int $amount): string;

}

در اینجا Payment یک Abstraction است.

این کلاس لازم نیست بداند پرداخت دقیقاً با چه سرویس یا API انجام می‌شود. فقط می‌داند که یک Gateway دارد و می‌تواند عملیات پرداخت را به آن واگذار کند.


مفهوم Implementation در Bridge Pattern

Implementation بخش پایین‌تر سیستم است که عملیات جزئی و فنی را انجام می‌دهد.

برای مثال:


interface PaymentGateway

{

    public function charge(int $amount): string;

}

این Interface قرارداد مشترک تمام درگاه‌های پرداخت را مشخص می‌کند.

سپس درگاه‌های مختلف آن را پیاده‌سازی می‌کنند:


class ZarinpalGateway implements PaymentGateway

{

    public function charge(int $amount): string

    {

        return "Payment through Zarinpal: {$amount}";

    }

}

و:


class StripeGateway implements PaymentGateway

{

    public function charge(int $amount): string

    {

        return "Payment through Stripe: {$amount}";

    }

}

در این ساختار:

  • Payment نقش Abstraction را دارد.
  • PaymentGateway نقش Implementation Interface را دارد.
  • ZarinpalGateway و StripeGateway Concrete Implementation هستند.

ساختار کلی Bridge Pattern

ساختار رایج Bridge Pattern شامل بخش‌های زیر است:


Abstraction

    |

    +── RefinedAbstraction



Implementation

    |

    +── ConcreteImplementationA

    +── ConcreteImplementationB

Abstraction

رابط یا منطق سطح بالای سیستم را مشخص می‌کند.

Refined Abstraction

نسخه‌های تخصصی‌تر Abstraction را پیاده‌سازی می‌کند.

Implementation

قرارداد عملیات فنی را تعریف می‌کند.

Concrete Implementation

پیاده‌سازی واقعی عملیات را انجام می‌دهد.

در نمونه‌های استاندارد Bridge، Abstraction یک Reference از نوع Implementation نگهداری می‌کند و عملیات را به آن واگذار می‌کند. <Cite refs={["turn0search0","turn0search2"]} />


# پیاده‌سازی Bridge Pattern در PHP

برای درک بهتر، یک سیستم نمایش صفحه می‌سازیم.

در این مثال:

  • Page مسئول ساختار صفحه است.
  • Renderer مسئول نحوه خروجی گرفتن است.
  • HtmlRenderer خروجی HTML تولید می‌کند.
  • JsonRenderer خروجی JSON تولید می‌کند.

مرحله اول: ساخت Renderer Interface

ابتدا قرارداد Renderer را ایجاد می‌کنیم:


interface Renderer

{

    public function renderTitle(string $title): string;



    public function renderText(string $text): string;



    public function renderImage(string $url): string;



    public function renderPage(array $parts): string;

}

هر Renderer باید این متدها را پیاده‌سازی کند.


مرحله دوم: ساخت HtmlRenderer

حالا Renderer مربوط به HTML را می‌سازیم:


class HtmlRenderer implements Renderer

{

    public function renderTitle(string $title): string

    {

        return "<h1>{$title}</h1>";

    }



    public function renderText(string $text): string

    {

        return "<p>{$text}</p>";

    }



    public function renderImage(string $url): string

    {

        return "<img src=\"{$url}\" alt=\"\">";

    }



    public function renderPage(array $parts): string

    {

        return implode("\n", $parts);

    }

}

این کلاس فقط مسئول تولید HTML است.


مرحله سوم: ساخت JsonRenderer

حالا Renderer مربوط به JSON را ایجاد می‌کنیم:


class JsonRenderer implements Renderer

{

    public function renderTitle(string $title): string

    {

        return json_encode([

            'title' => $title,

        ], JSON_UNESCAPED_UNICODE);

    }



    public function renderText(string $text): string

    {

        return json_encode([

            'text' => $text,

        ], JSON_UNESCAPED_UNICODE);

    }



    public function renderImage(string $url): string

    {

        return json_encode([

            'image' => $url,

        ], JSON_UNESCAPED_UNICODE);

    }



    public function renderPage(array $parts): string

    {

        return json_encode(

            $parts,

            JSON_UNESCAPED_UNICODE

        );

    }

}

در یک پروژه واقعی بهتر است ساختار JSON از ابتدا به شکل مشخص و استاندارد طراحی شود، اما این مثال برای درک Bridge مناسب است.


مرحله چهارم: ساخت Abstraction اصلی

حالا کلاس Page را می‌سازیم:


abstract class Page

{

    public function __construct(

        protected Renderer $renderer

    ) {

    }



    public function changeRenderer(Renderer $renderer): void

    {

        $this->renderer = $renderer;

    }



    abstract public function view(): string;

}

نکته مهم این کلاس، وابستگی آن به Interface است:


protected Renderer $renderer;

بنابراین Page به HtmlRenderer یا JsonRenderer وابسته نیست؛ بلکه به قرارداد Renderer وابستگی دارد.

همچنین متد زیر اجازه می‌دهد Implementation در زمان اجرا تغییر کند:


public function changeRenderer(Renderer $renderer): void


مرحله پنجم: ساخت SimplePage

حالا یک نوع صفحه ساده ایجاد می‌کنیم:


class SimplePage extends Page

{

    public function __construct(

        Renderer $renderer,

        private string $title,

        private string $content

    ) {

        parent::__construct($renderer);

    }



    public function view(): string

    {

        return $this->renderer->renderPage([

            $this->renderer->renderTitle($this->title),

            $this->renderer->renderText($this->content),

        ]);

    }

}

این کلاس مسئول منطق صفحه است، اما نحوه خروجی گرفتن را به Renderer واگذار می‌کند.


مرحله ششم: ساخت ProductPage

می‌توانیم نوع دیگری از صفحه را نیز ایجاد کنیم:


class ProductPage extends Page

{

    public function __construct(

        Renderer $renderer,

        private string $title,

        private string $description,

        private string $image

    ) {

        parent::__construct($renderer);

    }



    public function view(): string

    {

        return $this->renderer->renderPage([

            $this->renderer->renderTitle($this->title),

            $this->renderer->renderText($this->description),

            $this->renderer->renderImage($this->image),

        ]);

    }

}

حالا دو Abstraction داریم:


Page

    ├── SimplePage

    └── ProductPage

و دو Implementation:


Renderer

    ├── HtmlRenderer

    └── JsonRenderer


مرحله هفتم: استفاده از Bridge Pattern

حالا می‌توانیم صفحه را با Rendererهای مختلف ترکیب کنیم:


$htmlRenderer = new HtmlRenderer();



$page = new SimplePage(

    $htmlRenderer,

    'صفحه اصلی',

    'به سایت ما خوش آمدید'

);



echo $page->view();

خروجی:


<h1>صفحه اصلی</h1>

<p>به سایت ما خوش آمدید</p>

حالا همان صفحه را با JSON نمایش می‌دهیم:


$jsonRenderer = new JsonRenderer();



$page->changeRenderer($jsonRenderer);



echo $page->view();

در این حالت، بدون تغییر در کلاس SimplePage، خروجی آن تغییر می‌کند.

این دقیقاً همان هدف Bridge Pattern است: جداکردن منطق سطح بالا از جزئیات نحوه پیاده‌سازی.


# مثال کاربردی‌تر: Bridge Pattern در سیستم ارسال پیام

فرض کنید یک سیستم ارسال پیام داریم.

دو بُعد مستقل در این سیستم وجود دارد:

نوع پیام

  • پیام اطلاع‌رسانی
  • پیام تبلیغاتی
  • پیام هشدار

سرویس ارسال

  • SMS
  • Email
  • Telegram

اگر این دو بخش را با Inheritance ترکیب کنیم، تعداد زیادی کلاس خواهیم داشت.

اما با Bridge می‌توانیم آن‌ها را جدا کنیم.


ساخت MessageSender Interface


interface MessageSender

{

    public function send(

        string $recipient,

        string $message

    ): bool;

}


پیاده‌سازی SMS


class SmsSender implements MessageSender

{

    public function send(

        string $recipient,

        string $message

    ): bool {

        echo "Sending SMS to {$recipient}: {$message}";



        return true;

    }

}


پیاده‌سازی Email


class EmailSender implements MessageSender

{

    public function send(

        string $recipient,

        string $message

    ): bool {

        echo "Sending Email to {$recipient}: {$message}";



        return true;

    }

}


ساخت Abstraction پیام


abstract class Message

{

    public function __construct(

        protected MessageSender $sender

    ) {

    }



    abstract public function send(

        string $recipient

    ): bool;

}


ساخت NotificationMessage


class NotificationMessage extends Message

{

    public function __construct(

        MessageSender $sender,

        private string $text

    ) {

        parent::__construct($sender);

    }



    public function send(string $recipient): bool

    {

        return $this->sender->send(

            $recipient,

            $this->text

        );

    }

}


ساخت AlertMessage


class AlertMessage extends Message

{

    public function __construct(

        MessageSender $sender,

        private string $text

    ) {

        parent::__construct($sender);

    }



    public function send(string $recipient): bool

    {

        return $this->sender->send(

            $recipient,

            "ALERT: {$this->text}"

        );

    }

}


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


$smsSender = new SmsSender();



$notification = new NotificationMessage(

    $smsSender,

    'سرویس شما تمدید شد'

);



$notification->send('09120000000');

حالا می‌توانیم همان نوع پیام را با Email ارسال کنیم:


$emailSender = new EmailSender();



$notification = new NotificationMessage(

    $emailSender,

    'سرویس شما تمدید شد'

);



$notification->send('user@example.com');

همچنین:


$alert = new AlertMessage(

    $smsSender,

    'موجودی کیف پول شما کم است'

);



$alert->send('09120000000');

در این مثال، نوع پیام و سرویس ارسال از یکدیگر مستقل هستند.


# Bridge Pattern در Laravel

در Laravel می‌توان از Bridge برای جداکردن منطق کسب‌وکار از سرویس‌های زیرساختی استفاده کرد.

برای مثال در پروژه‌ای که با چند سرویس پیامک کار می‌کند، می‌توانیم Interface زیر را تعریف کنیم:


namespace App\Contracts;



interface SmsProvider

{

    public function send(

        string $mobile,

        string $message

    ): bool;

}

سپس Providerهای مختلف را ایجاد کنیم:


namespace App\Services\Sms;



use App\Contracts\SmsProvider;



class MelipayamakProvider implements SmsProvider

{

    public function send(

        string $mobile,

        string $message

    ): bool {

        // ارسال پیامک با ملی پیامک



        return true;

    }

}

و:


namespace App\Services\Sms;



use App\Contracts\SmsProvider;



class KavenegarProvider implements SmsProvider

{

    public function send(

        string $mobile,

        string $message

    ): bool {

        // ارسال پیامک با کاوه نگار



        return true;

    }

}

حالا منطق سطح بالای پیام را جدا می‌کنیم:


namespace App\Services;



use App\Contracts\SmsProvider;



class ServiceNotification

{

    public function __construct(

        private SmsProvider $provider

    ) {

    }



    public function sendRenewalMessage(

        string $mobile,

        string $serviceName

    ): bool {

        $message = "سرویس {$serviceName} با موفقیت تمدید شد.";



        return $this->provider->send(

            $mobile,

            $message

        );

    }

}

در این ساختار:

  • ServiceNotification نقش Abstraction را دارد.
  • SmsProvider نقش Implementation Interface را دارد.
  • Providerهای پیامک، Concrete Implementation هستند.

با این روش، منطق تمدید سرویس به Provider خاصی وابسته نمی‌شود.


# اتصال Bridge به Service Container لاراول

می‌توانیم Provider موردنظر را در Service Container ثبت کنیم:


use App\Contracts\SmsProvider;

use App\Services\Sms\KavenegarProvider;



$this->app->bind(

    SmsProvider::class,

    KavenegarProvider::class

);

سپس Laravel هنگام ساخت ServiceNotification، پیاده‌سازی مناسب را تزریق می‌کند.

در این حالت، اگر بعداً بخواهیم Provider را تغییر دهیم، لازم نیست منطق اصلی Notification را تغییر دهیم.

فقط Binding را عوض می‌کنیم:


$this->app->bind(

    SmsProvider::class,

    MelipayamakProvider::class

);

البته در پروژه‌های واقعی بهتر است تنظیم Provider از طریق فایل Config انجام شود تا تغییر سرویس بدون ویرایش چندین بخش از برنامه امکان‌پذیر باشد.


# تفاوت Bridge و Adapter Pattern

Bridge و Adapter از نظر ساختار ظاهری شباهت زیادی دارند، اما هدفشان متفاوت است.

Bridge

Bridge معمولاً از ابتدا برای جداکردن دو بُعد مستقل طراحی می‌شود.

مثلاً:


Page + Renderer

Payment + Gateway

Message + Sender

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

Adapter

Adapter معمولاً زمانی استفاده می‌شود که دو کلاس یا سرویس موجود Interface سازگاری ندارند و باید آن‌ها را با یکدیگر هماهنگ کنیم.

به زبان ساده:


Bridge:

طراحی مستقل دو بخش از ابتدا



Adapter:

سازگارکردن دو بخش موجود

Refactoring.Guru نیز Bridge را بیشتر برای طراحی مستقل دو سلسله‌مراتب و Adapter را برای سازگارکردن کلاس‌های موجود معرفی می‌کند. <Cite refs={["turn0search2"]} />


# تفاوت Bridge و Strategy Pattern

Bridge و Strategy هر دو از Composition استفاده می‌کنند و در هر دو، یک کلاس به Object دیگری وابسته می‌شود.

اما هدف آن‌ها متفاوت است.

Strategy

Strategy برای انتخاب یا تعویض الگوریتم استفاده می‌شود.

مثلاً:


PaymentStrategy

    ├── ZarinpalStrategy

    ├── StripeStrategy

    └── PaypalStrategy

Bridge

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

مثلاً:


PaymentType

    +

PaymentGateway

در Strategy معمولاً تمرکز روی تعویض الگوریتم است، اما در Bridge تمرکز روی مستقل‌کردن دو سلسله‌مراتب است.

ساختار Bridge و Strategy ممکن است شبیه باشند، اما مسئله‌ای که حل می‌کنند متفاوت است. <Cite refs={["turn0search2"]} />


# مزایای Bridge Pattern

1. کاهش تعداد Subclassها

به‌جای ساخت کلاس برای تمام ترکیب‌ها، دو سلسله‌مراتب مستقل ایجاد می‌کنیم.

2. توسعه مستقل

می‌توان Abstraction را بدون تغییر در Implementation توسعه داد و برعکس.

3. رعایت اصل Open/Closed

برای اضافه‌کردن نوع جدید، معمولاً کافی است کلاس جدیدی در یکی از سلسله‌مراتب ایجاد کنیم.

4. کاهش وابستگی

Abstraction به Interface وابسته است، نه به یک پیاده‌سازی مشخص.

5. امکان تغییر Implementation در زمان اجرا

اگر طراحی اجازه دهد، می‌توان Implementation را در زمان اجرا تغییر داد.

6. تست‌پذیری بهتر

در تست‌ها می‌توان یک Fake یا Mock از Implementation به Abstraction تزریق کرد.


# معایب Bridge Pattern

1. افزایش تعداد کلاس‌ها

اگرچه تعداد کلاس‌های ترکیبی کاهش پیدا می‌کند، اما ممکن است تعداد Interfaceها و کلاس‌های مستقل بیشتر شود.

2. پیچیدگی اولیه

برای پروژه‌های کوچک، این ساختار ممکن است بیش از نیاز باشد.

3. نیاز به طراحی درست

اگر دو بُعد واقعاً مستقل نباشند، استفاده از Bridge می‌تواند ساختار را غیرضروری پیچیده کند.

4. دشواری برای افراد مبتدی

مفاهیمی مانند Abstraction، Implementation و Composition ممکن است در ابتدا کمی پیچیده باشند.


# چه زمانی از Bridge Pattern استفاده کنیم؟

Bridge معمولاً زمانی مناسب است که:

  • یک کلاس در چند بُعد مستقل تغییر می‌کند؛
  • تعداد Subclassها در حال افزایش است؛
  • منطق سطح بالا نباید به سرویس خاصی وابسته باشد؛
  • چند Provider یا Platform مختلف دارید؛
  • باید Implementation در زمان اجرا تغییر کند؛
  • می‌خواهید بخش‌های مختلف سیستم مستقل تست و توسعه داده شوند.

مثال‌های رایج عبارت‌اند از:

  • چند نوع درگاه پرداخت؛
  • چند سرویس پیامک؛
  • چند نوع خروجی مانند HTML و JSON؛
  • چند سرویس ذخیره‌سازی؛
  • چند Provider برای API؛
  • چند نوع گزارش‌گیری؛
  • چند نوع Renderer برای یک صفحه.

Bridge برای پشتیبانی از چند Platform یا Provider مختلف، مانند سرویس‌های API یا پایگاه داده، کاربرد مناسبی دارد. <Cite refs={["turn0search0","turn0search2"]} />


# چه زمانی از Bridge استفاده نکنیم؟

اگر فقط یک نوع Implementation دارید و احتمال توسعه آن کم است، شاید Bridge لازم نباشد.

مثلاً:


class Report

{

    public function generate(): string

    {

        return 'Report';

    }

}

در این شرایط ساخت Interface و چند کلاس جداگانه ممکن است فقط پیچیدگی ایجاد کند.

همچنین اگر مسئله فقط انتخاب بین چند الگوریتم است، Strategy احتمالاً انتخاب ساده‌تر و واضح‌تری خواهد بود.


# تست Bridge Pattern با PHPUnit

برای تست می‌توانیم یک Fake Renderer بسازیم:


class FakeRenderer implements Renderer

{

    public function renderTitle(string $title): string

    {

        return "TITLE: {$title}";

    }



    public function renderText(string $text): string

    {

        return "TEXT: {$text}";

    }



    public function renderImage(string $url): string

    {

        return "IMAGE: {$url}";

    }



    public function renderPage(array $parts): string

    {

        return implode('|', $parts);

    }

}

حالا تست می‌کنیم که SimplePage از Renderer استفاده می‌کند:


public function testSimplePageUsesRenderer(): void

{

    $renderer = new FakeRenderer();



    $page = new SimplePage(

        $renderer,

        'Home',

        'Welcome'

    );



    $result = $page->view();



    $this->assertSame(

        'TITLE: Home|TEXT: Welcome',

        $result

    );

}

همچنین می‌توان تغییر Renderer را تست کرد:


public function testRendererCanBeChanged(): void

{

    $htmlRenderer = new HtmlRenderer();

    $jsonRenderer = new JsonRenderer();



    $page = new SimplePage(

        $htmlRenderer,

        'Home',

        'Welcome'

    );



    $htmlResult = $page->view();



    $page->changeRenderer($jsonRenderer);



    $jsonResult = $page->view();



    $this->assertNotSame(

        $htmlResult,

        $jsonResult

    );

}


# اشتباهات رایج در استفاده از Bridge Pattern

اشتباه اول: استفاده از Inheritance برای تمام ترکیب‌ها

اگر چند بُعد مستقل دارید، ساخت کلاس‌های ترکیبی باعث رشد سریع Hierarchy می‌شود.

اشتباه دوم: وابستگی مستقیم به Concrete Class

بهتر است Abstraction به Interface وابسته باشد:


protected Renderer $renderer;

نه به یک کلاس مشخص:


protected HtmlRenderer $renderer;

اشتباه سوم: استفاده برای پروژه‌های بسیار ساده

Bridge برای هر کلاس کوچک لازم نیست.

اشتباه چهارم: اشتباه گرفتن Bridge با Adapter

Adapter برای سازگارکردن Interfaceهای موجود است، اما Bridge برای جداکردن دو سلسله‌مراتب مستقل طراحی می‌شود.

اشتباه پنجم: قرار دادن منطق Implementation داخل Abstraction

اگر Page شروع به ساخت HTML، JSON و XML کند، جداسازی از بین می‌رود.


# جمع‌بندی Bridge Pattern در PHP

Bridge Pattern یک Structural Design Pattern است که Abstraction را از Implementation جدا می‌کند.

در این الگو، به‌جای اینکه برای تمام ترکیب‌های ممکن کلاس‌های جداگانه بسازیم، دو سلسله‌مراتب مستقل ایجاد می‌کنیم و آن‌ها را با Composition به یکدیگر متصل می‌کنیم.

ساختار کلی آن به شکل زیر است:


Abstraction

    |

    v

Implementation

نمونه‌های رایج استفاده از Bridge عبارت‌اند از:

  • Page و Renderer؛
  • Payment و PaymentGateway؛
  • Message و MessageSender؛
  • Report و ReportFormatter؛
  • Service و API Provider.

مهم‌ترین مزیت Bridge این است که می‌توان هر بخش را مستقل از بخش دیگر توسعه داد. همچنین با استفاده از Interface و Dependency Injection، تست‌پذیری و انعطاف‌پذیری سیستم افزایش پیدا می‌کند.

با این حال، Bridge برای تمام پروژه‌ها مناسب نیست. اگر سیستم ساده باشد یا فقط به انتخاب یک الگوریتم نیاز داشته باشید، Strategy یا حتی یک کلاس ساده می‌تواند انتخاب بهتری باشد.


# سوالات متداول Bridge Pattern در PHP

Bridge Pattern در PHP چیست؟

Bridge Pattern الگویی Structural است که Abstraction و Implementation را از یکدیگر جدا می‌کند تا هرکدام مستقل توسعه پیدا کنند.

مهم‌ترین هدف Bridge Pattern چیست؟

هدف اصلی آن جلوگیری از افزایش تعداد Subclassها در شرایطی است که یک سیستم در چند بُعد مستقل توسعه پیدا می‌کند.

Abstraction در Bridge چه نقشی دارد؟

Abstraction منطق سطح بالای سیستم را مدیریت می‌کند و عملیات فنی را به Implementation واگذار می‌کند.

Implementation در Bridge چیست؟

Implementation قراردادی برای عملیات فنی تعریف می‌کند و Concrete Implementationها آن را پیاده‌سازی می‌کنند.

تفاوت Bridge و Adapter چیست؟

Bridge برای جداکردن دو بخش مستقل از ابتدا طراحی می‌شود، اما Adapter معمولاً برای سازگارکردن دو کلاس یا سرویس موجود استفاده می‌شود.

تفاوت Bridge و Strategy چیست؟

Strategy بیشتر برای تعویض الگوریتم کاربرد دارد، اما Bridge برای جداکردن دو سلسله‌مراتب مستقل طراحی می‌شود.

آیا Bridge Pattern در Laravel کاربرد دارد؟

بله. می‌توان از آن برای جداکردن منطق کسب‌وکار از Providerهای پیامک، درگاه‌های پرداخت، سرویس‌های ذخیره‌سازی و APIهای مختلف استفاده کرد.

آیا Bridge همیشه انتخاب مناسبی است؟

خیر. در پروژه‌های کوچک یا زمانی که فقط یک Implementation وجود دارد، استفاده از Bridge ممکن است پیچیدگی غیرضروری ایجاد کند.

نظرات (0)

نظرات پس از تأیید مدیر نمایش داده می‌شوند

هنوز نظری ثبت نشده است؛ اولین نفر باشید!

مقالات مرتبط

ساخت CMS با Laravel 12؛ آموزش ساخت سیستم مدیریت محتوا از صفر

ساخت CMS با Laravel 12؛ آموزش ساخت سیستم مدیریت محتوا از صفر

۲۴ دقیقه
ساخت فروشگاه اینترنتی با Laravel 12؛ آموزش پروژه‌محور از صفر تا طراحی هسته فروشگاه

ساخت فروشگاه اینترنتی با Laravel 12؛ آموزش پروژه‌محور از صفر تا طراحی هسته فروشگاه

۲۲ دقیقه
ساخت Marketplace با Laravel؛ آموزش طراحی فروشگاه چندفروشندگی

ساخت Marketplace با Laravel؛ آموزش طراحی فروشگاه چندفروشندگی

۲۲ دقیقه
مدیریت Queueهای سنگین در Laravel؛ آموزش پردازش کارهای طولانی

مدیریت Queueهای سنگین در Laravel؛ آموزش پردازش کارهای طولانی

۲۲ دقیقه