ویرگول
ورودثبت نام
سجاد نصیری
سجاد نصیری
خواندن ۳ دقیقه·۱۰ ماه پیش

دیزاین پترن Strategy به سبک لاراول

همانطور که می دانید از دیزاین پترن Strategy در مواقعی استفاده می کنیم که چند implementation برای یک کار یکسان داریم و می خواهیم بر اساس یک استراتژی خاص بین این implementation ها انتخاب کنیم که کدام یک اجرا شود. برای مثال تصور کنید که چندین درگاه بانکی داریم از جمله زرین پال، بانک ملی، بانک ملت و... که هر کدام نحوه پیاده سازی و کانفیگ خاص خودشان را دارند. حالا اگر بخواهیم کاربر انتخاب کند که با کدام درگاه، پرداخت را انجام دهد یا مثلا اگر مبلغ پرداخت بیش از 10 ملیون تومان فقط با درگاه بانک ملی پرداخت انجام شود و... باید از دیزاین پترن استراتژی استفاده کنیم.( برای یادگیری دیزاین پترن استراتژی در php می توانید از لینک اشاره شده استفاده کنید)

پیش از مطالعه ادامه این نوشته بهتر است اگر با dependency injection در لاراول آشنایی ندارید، مقاله service container و تزریق وابستگی ها در laravel را مطالعه کنید.

هدف ما این است که دیزاین پترن استراتژی را از طریق service provider های لاراول و سیستم پیشرفته تزریق وابستگی های این فریمورک انجام دهیم. همچنین فرض کنید که کاربر قرار است در هنگام پرداخت، در قسمت front سایت نوع درگاهی که می خواهد را مشخص کند و نام درگاه انتخاب شده در پارامتری به نام gateway برای ما ارسال می شود.

  1. ابتدا یک interface ایجاد می کنیم که همه درگاه های بانکی ما باید از آن implement کنند:
<?php namespace App\Contracts; interface Gateway { public function payment($amount); }

2. سپس کلاس های مربوط به بانک های مختلف را می سازیم:

<?php namespace App\Services; use App\Contracts\Gateway; use Illuminate\Support\Facades\Http; class MelliGateway implements Gateway { public function payment($amount) { Http::post('https://mellibank', [ 'amount' => $amount, 'token' => '123' // other parameters ]); // other codes } }
<?php namespace App\Services; use App\Contracts\Gateway; use Illuminate\Support\Facades\Http; class MellatGateway implements Gateway { public function payment($amount) { Http::post('https://mellatbank', [ 'amount' => $amount, 'token' => '456' // other parameters ]); // other codes } }

3. پس از این که کلاس های implement شده از اینترفیس Gateway را برای درگاه های مختلف ایجاد کردیم، باید آن ها را در service container ثبت کنیم تا بتوانیم به کنترلر ها، کلاس خا و دیگر بخش های برنامه تزریقشان کرده و از آنها استفاده کنیم. بدین منظور با دستور زیر یک service provider می سازیم:

php artisan make:provider GatewayServiceProvider

پس از ساخته شدن GatewayServiceProvider در آن کدهایی مشابه زیر می نویسیم:

<?php namespace App\Providers; use App\Contracts\Gateway; use App\Services\MellatGateway; use App\Services\MelliGateway; use Illuminate\Http\Client\Request; use Illuminate\Support\ServiceProvider; class GatewayServiceProvider extends ServiceProvider { /** * Register services. * * @return void */ public function register() { // } /** * Bootstrap services. * * @return void */ public function boot() { $this->app->singleton(Gateway::class, function (Request $request){ if ($request->gateway == 'melli') { return new MelliGateway(); } elseif ($request->gateway == 'mellat') { return new MellatGateway(); } }); } }

به دلیل این که می خواهیم از سرویس Request که خود نیاز به ثبت شدن درون service container دارد استفاده کنیم تا از طریق آن پارامتر gateway ریکوئست جاری را به دست آوریم، عملیات bind کردن را در متد boot انجام داده ایم. سپس پارامتر gateway ریکوئست جاری را گرفته ایم و بررسی کردیم که اگر melli بود درگاه بانک ملی و اگر mellat بود درگاه بانک ملت برگردانده شود.

4. در مرحله بعد باید GatewayServiceProvider را در service container ثبت کنیم. برای این کار به config/app.php رفته و در آرایه 'providers' پرووایدری که ساختیم را اضافه می کنیم:

'providers' => [ // other providers /* * Application Service Providers... */ App\Providers\AppServiceProvider::class, App\Providers\AuthServiceProvider::class, // App\Providers\BroadcastServiceProvider::class, App\Providers\EventServiceProvider::class, App\Providers\RouteServiceProvider::class, // our gateway service provider: App\Providers\GatewayServiceProvider::class ]

5. پس از این مرحله می توانیم به صورت type-hint در سرتاسر کدهای لاراولی مان به Gateway دسترسی داشته باشیم:

<?php namespace App\Http\Controllers; use App\Contracts\Gateway; use Illuminate\Http\Request; class PaymentController extends Controller { public function pay(Request $request, Gateway $gateway) { // validate request yourself $gateway->payment($request->amount); } }

و به این صورت خیلی زیبا و تمیز توانستیم دیزاین پترن strategy را در لاراول پیاده سازی کنیم?

دیزاین پترن
backend developer
شاید از این پست‌ها خوشتان بیاید