برچسب: دیزاین پترن های php

  • دیزاین پترن singleton در PHP

    در ادامه بحث هامون در مورد دیزاین پترن ها امروز میخوام بصورت خلاصه در مورد singleton design pattern بنویسم که فکر میکنم به درد خیلی هاتون بخوره و خیلی از پیچیدگی کد نویسی رو براتون کمتر کنه. بصورت خلاصه و مفید اگه بخوام بگم این دیزاین پترن همونطور که از اسمش پیداست از تکرار جلوگیری میکنه و جاهایی استفاده میشه که بخوایم یه کد تکراری رو فقط یکبار بنویسیم. پس سینگلتون جاهایی به کارمون میاد که ما به یه نمونه از شی بصورت گلوبال میخوایم دسترسی داشته باشیم. مثلا شما ممکنه مجبور باشید توی یک سیستم بارها به دیتابیس وصل بشید. یا ممکنه بخواید از api یه سایت دیگه هر چند بار پشت سر هم استفاده کنید یا هر چیز دیگه ای که خودتون صلاح میدونید… با مثال توضیح میدم که ایده ی این الگو چطور هست. در زیر یه پیاده سازی پایه از این الگو رو میبینیم :

    class Database
    {
        public static function Instance()
        {
            static $inst = null;
            if ($instnce === null) {
                $instnce = new Database();
            }
            return $instnce;
        }
    
        public function getUsers()
        {
            return 'users...';
        }
        
        public function getPosts()
        {
            return 'posts...';
        }
    }
    
    $users = Database::Instance()->getUsers();
    $posts = Database::Instance()->getPosts();

    همونطور که میبینید Instance  به صورت متد استاتیک تعریف شده و بصورت استاتیک بهش دسترسی پیدا میکنیم.

  • دیزاین پترن Simple Factory در PHP

    سلام، بعد از یه وقفه ی نسبتا طولانی امروز دوباره تصمیم گرفتم که این وبلاگ متروکه رو آپدیت کنم و یسری پست که احساس میکنم خوبن رو اینجا بفرستم… البته پستای قبلیمو دارم میبینم اکثرا چرت و پرتن و ارزش خوندن ندارن ولی به هر حال وبلاگ خودمه و کلی پول هاست و دامین دادم و دوس دارم که بعنوان یادگاری همینجا باشن و کسی اگه اعتراض داره میتونه مراتب اعتراضش رو تحت یک کامنت برام ارسال کنه تا بررسی و پاسخ داده بشه 🙂

    Design patternها یا فارسیش میشه احتمالا الگوهای طراحی نرم افزار توی همه زبان ها خیلی خیلی مهمن. معمولا وقتی کدی مینویسیم که قرار نیست در آینده گسترش داده بشه خیالمون راحته و از یجای کار شروع میکنیم و یجا تموم میکنیم و کار رو تحویل میدیم، ولی وقتی کارفرما میگه که “در آینده قراره امکانات زیادی از قبیل فلان۱ و فلان۲ و… به سیستم اضافه بشه”، اونجا باید یه فکر پایه ای تر برای سیستم داشته باشیم. طوری که اگه قرار شد یه بخش جدید رو به سیستم اضافه کنیم مجبور نباشیم تو بخشای قبلی دست اندازی کنیم یا حداقل کم مجبور باشیم(!).

    فرض کنید که میخواید یه فروشگاه بنویسید که ادمین روزی چند تا محصول از نوع اسباب بازی به سیستم اضافه میکنه. ابتدایی ترین روشی که به فکر همه ما میرسه اینه که یه کلاس ایجاد کنیم تحت نام Product  و توی اون درج، اصلاح، حذف و … محصول که فعلا اسباب بازی هست رو انجام بدیم. یه چیزی شبیه این :

    <?php
    class Product {
        public function __construct($name) {}
    
        public function save() {}
    }
    $product = new Product('first toy');
    $product->save();

    تا اینجا همه چی خوبه و شما در آرامش قبل از طوفان به سر میبرید! مشکل زمانی پیش میاد که مجبور بشید مثلا بجز اسباب بازی ، کتاب هم در فروشگاهتون بفروشید. اینجا دیگه روش ایجاد و اصلاح و … فرق میکنه و نمیتونید همین متد های قبل رو استفاده کنید. توی دیزاین پترن بالا شما مجبورید یه $type  زمان نمونه گیری از کلاس بگیرید و توی هر متد if و else بذارید و بگید اگه این دسته بود این کارو بکن و اگه… که قطعا روش خوبی نیست و مثلا وقتی چنتا دسته دیگه بعدها اضافه بشه کدمون خیلی داغون میشه.

    نحوه ی پیاده سازی دیزاین پترن Simple Factory در PHP

    سیمپل فکتوری دیزاین پترن میگه که شما این کارو بکنید :

    اول یه کلاس factory بسازید :

    class ProductFactory {
      public function __construct(){ }
    
      public static function create($type){
         if ($type == '')
            throw new Exception('invalid product type');
         else {
            $className = 'product_' . ucfirst($type);
            if (class_exists($className))
               return new $className;
            else
               throw new Exception('Product type not found');
         }
      }
    }
    

    حالا واسه ساخت اسباب بازی از روش خیلی ساده زیر استفاده کنید :  

    class product_Toy
    {
      public function __construct(){
         echo "toy is creating";
      }
    }
    $toy = ProductFactory::create('toy');
    

    حالا اگه یه دسته جدید مثل کتاب به محصولاتون اضافه شه خیلی راحت میتونید کلاسش رو بسازید محصولتون رو اضافه کنید :

    class product_Book
    {
      public function __construct(){
         echo "book is creating";
      }
    }
    $book = ProductFactory::create('book');
    

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

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

    امیدوارم کمکتون کرده باشم و خوشحال میشم نظراتتون رو بشنوم 🙂

  • کلاسهای abstract یا انتزاعی در PHP

    کلاسهای abstract در اکثر زبان های شئ گرا وجود دارند. کلاسهایی هستند که قابل نمونه گیری نیستند ، و سایر کلاسها فقط میتوانند از آنها ارث بری کنند.

    فرض کنید که شما یک کلاس animal دارید و میخواهید همه حیوانات از آن کلاس یا شئ مشتق شوند ، خود کلاس animal به تنهایی قابل نمونه گیری نیست. چون ما موجود حیون نداریم و مثلا گربه با به ارث بردن بخشی از ویژگی های حیوان به موجودیت میرسد . پس دلیل اینکه اسم این نوع کلاسها را abstract گذاشته اند هم قابل درک هست.

    کاربرد کلاسهای abstract

    حتما الان این سوال براتون پیش اومده که ” چه کاریه از abstract استفاده کنیم ؟ کلاس معمولی درست میکنیم ، ازش ارثم میبریم 🙂 “

    سوال به جایی هم هست ، در پروژه های بزرگ برای خوانایی برنامه از abstract ها استفاده میکنند . شما وقتی یک کلاس abstract رو میبینید، خیلی راحت میفهمید که این تابع قابل نمونه گیری نیست و یک کلاس برای ارث برده شدن هست. در پروژه های کوچیک این مسئله زیاد خودش رو نشون نمیده ولی در پروژه های بزرگ خیلی کاربرد داره. مثلا همین فریمورک لاراول خودمون خیلی جاها از همین نوع کلاسها استفاده کرده.

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

    نحوه ی تعریف یک کلاس abstract

    برای تعریف یک کلاس انتزاعی از کلمه کلیدی abstract قبل از class  استفاده میکنیم :

    abstract class Animal
    {
        public $name;
        public $age;
        
        public function Describe()
        {
            return $this->name . ", " . $this->age . " years old";    
        }
        
        abstract public function Greet();
    }

    الان اگه شما از کلاس بالا نمونه بگیرید با اررور مواجه میشید. طبیعی هم هست دیگه 🙂

    یادتون باشه درون کلاس abstract تون میتونید متد هایی رو تعریف کنید و از اونها استفاده کنید و اون متد ها میتونن abstract باشن یا نه…

    اگه متدی رو از نوع abstract تعریف کردید ، توسعه دهنده های دیگه رو مجبور میکنید : در صورتی که از کلاس شما کلاسی رو به ارث بردن ، حتما نابع رو دوباره بنویسن. مثلا هر کلاسی که از کلاس بالا مشتق بشه ، باید متد Greet رو دوباره بنویسه.

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

    کلاس زیر از کلاس بالا مشتق شده :

    class Dog extends Animal
    {
        public function Greet()
        {
            return "Woof!";    
        }
        
        public function Describe()
        {
            return parent::Describe() . ", and I'm a dog!";    
        }
    }

    همونطور که میبینید ما مجبور بودیم که متد Greet() رو بازنویسی کنیم. حالا میتونیم از کلاس Dog بصورت زیر نمونه بگیریم :

    $animal = new Dog();
    $animal->name = "Bob";
    $animal->age = 7;
    echo $animal->Describe();
    echo $animal->Greet();

    کاربرد متدهای Abstract در دیزاین پترن template method

    دیزاین پترن ها یا الگوهای طراحی نرم افزار الگوهایی مشخص و روتین هستند که بین برنامه نویس ها شناخته شده هستن و یجورایی توسعه دهنده ها میتونن آدرس بدن که فلان کد رو چجوری توسعه دادن بدون اینکه نیاز باشه جزییات رو بگن. یکی از این دیزاین پترن ها template method هست. یه تایم هایی هست که شما کارای تکراری زیادی توی دو تا کلاس دارید و میخواید از اون تکرار جلوگیری کنید. مثلا حالت زیر رو در نظر بگیرید:

    <?php
    
    
    class GatewayPay {
        public function changeOrderStatus(){
            var_dump('change order status');
        }
        public function goToGateway(){
            var_dump('redirecting to gateway.');
        }
    }
    
    class WalletPay {
        public function changeOrderStatus()
        {
            var_dump('change order status');
        }
        public function changeUserCredit(){
            var_dump('changing user credit.');
        }
    }

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

    <?php
    
    abstract class Pay
    {
        public function changeOrderStatus()
        {
            var_dump('change order status');
        }
    
        abstract public function finalize();
    }
    
    
    class GatewayPay implements Pay {
    
        public function finalize(){
            var_dump('redirecting to gateway.');
        }
    }
    
    class WalletPay implements Pay {
    
        public function finalize(){
            var_dump('changing user credit.');
        }
    }
    

    میبینید که متد تکراری رو بردیم بالا توی کلاس دیگه و متدهای دیگه رو هم نام کردیم و کارهای غیر تکراری رو توشون گذاشتیم. اگه حرفامو متوجه شدید بهتون تبریک میگم. شما یک دیزاین پترن به اسم Template Method رو به همین آسونی یاد گرفتید 🙂 جزییات بیشتر رو توی سایت زیر بخونید:

    https://refactoring.guru/design-patterns/template-method