آشنایی با الگوی طراحی Singleton


در این آموزش با یک الگوی طراحی تحت عنوان Singleton Design Pattern آشنا می‌شویم و همچنین در قالب مثالی کاربردی در زبان PHP به بررسی لزوم به‌کارگیری آن در برنامه‌نویسی شیئ‌گرا خواهیم پرداخت.

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

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

- تسک‌های مربوط به اتصال به برخی سرویس‌های API به طوری که به ازای هر بار اتصال هزینه‌ای برای آن پرداخت شود.
- برخی کلاس‌هایی که وظایفی همچون تشخیص نوع دیوایس مورد استفادۀ کاربر را بر عهده دارند که این امر ممکن است منجر به کاهش سرعت اپلیکیشن گردد.
- برقراری کانکشن با دیتابیس که این موضوع نیز زمان‌بر بوده و تکرار مجدد آن در هر بار اجرا منجر به کاهش سرعت اپلیکیشن می‌گردد (که در این آموزش این مسأله مورد بررسی قرار خواهد گرفت.)

در همین راستا، برای درک بهتر ساختار دیزاین پترن سینگلتون مثالی را در نظر می‌گیریم که در آن قصد داریم تا کلاسی را به منظور برقراری کانکشن با دیتابیس مربوط به وب اپلیکیشن فرضی خود پیاده‌سازی می‌کنیم که در چنین شرایطی اگر بخواهیم اپلیکیشن خود را بدون استفاده از دیزاین پترن سینگلتون پیاده‌سازی کنیم، پوشه‌ای تحت عنوان singleton-design-pattern در لوکال‌هاست ساخته و فایلی به نام ConnectDbWOSingleton.php داخل آن ایجاد می‌کنیم و در ادامه فایل مذکور را بدین شکل تکمیل می‌کنیم:

class ConnectDbWithoutSingleton {
    private $conn;
    private $host = 'localhost';
    private $username = 'root';
    private $pass = 'root';
    private $dbname = 'sokanacademy';

    public function __construct() {
        $this->conn = new PDO("mysql:host={$this->host}; dbname={$this-> dbname }", 
        $this->username, $this->pass,
        array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'"));
    }

    public function getConnection() {
        return $this->conn;
    }
}

پیش از هر توضیحی، لازم به یادآوری است که کلیهٔ فایل‌های این آموزش با دستور php?> شروع می‌شوند که به دلیل شلوغ نشدن کدها، از نوشتن آن در تمامی اسکریپت‌ها خودداری کرده‌ایم. همان‌طور که در کد فوق می‌بینید، از لایبرری PDO برای برقراری ارتباط با دیتابیس استفاده کرده‌ایم که برای آشنایی با نحوۀ پیاده‌سازی آن نیز می‌توانید به مقالۀ ارتباط با دیتابیس در PHP از طریق لایبرری PDO مراجعه نمایید.

در تفسیر کد فوق باید بگوییم که ابتدا کلاسی تحت عنوان ConnectDbWithoutSingleton ساخته و در آن یکسری پراپرتی از جنسِ پرایوت تعریف کرده‌ایم به طوری که متغیر conn$ به منظور نگهداری آبجکتی که مسئول برقراری کانکشن با دیتابیس می‌باشد تعریف شده و host$ به منظور نگهداری نام هاست است که در اینجا ما آن را از نوع localhost انتخاب کرده‌ایم چرا که هم دیتابیس و هم اسکریپت‌های آموزش قرار است تا روی یک سرور اجرا شوند و پراپرتی username$ نیز به منظور نگهداری نام‌کاربری مورد استفاده برای اتصال به مای‌اس‌کیوال تعریف شده است که در این مثال نام کاربری مربوط به phpMyAdmin نصب‌شده روی سیستم root است و در ادامه پراپرتی pass$ را به منظور نگهداری رمزعبور مورد استفاده برای اتصال به دیتابیس تعریف کرده‌ایم که این مورد نیز برابر با root در نظر گرفته شده است و در نهایت هم پراپرتی dbname$ را برای نگهداری نام دیتابیس تعریف کرده‌ایم که در این مثال sokanacademy در نظر گرفته شده است.

نکته
لازم به یادآوری است که بسته به محیط توسعه‌ای که از آن استفاده می‌کنید، نام‌کاربری و رمزعبور phpMyAdmin می‌تواند با آنچه در این آموزش مطرح شد متفاوت باشد.

همچنین سطح دسترسی پراپرتی‌های فوق را بدین دلیل private تعریف کرده‌ایم که صرفاً در داخل کانستراکتور کلاس فوق مورد استفاده قرار خواهند گرفت و از همین روی بهتر است پرایوت در نظر گرفته شوند تا از سایر بخش‌های وب اپلیکیشن‌مان قابل‌روئیت نباشند.

در ادامه یک کانستراکتور ساخته‌ایم و در آن گفته‌ایم در صورت ساخت آبجکتی از روی کلاس ConnectDbWithoutSingleton فوراً آبجکتی از روی کلاس PDO ساخته شود که این آبجکت چهار آرگومان ورودی می‌گیرد که آرگومان اول مربوط به نوع سیستم مدیریت دیتابیس، نام دیتابیس و سرور است که نام سیستم مدیریت دیتابیس را mysql در نظر گرفته و در ادامه مقدار منتسب به هر یک از پراپرتی‌های host$ و dbname$ را از طریق علائم {} به عنوان پارامتر ورودی به آن داده‌ایم و بدین ترتیب مفسر پی‌اچ‌پی نام پراپرتی‌های مذکور را به عنوان استرینگ معمولی داخل علائم " " نخوانده و مقادیر منتسب به آن‌ها را به ترتیبِ localhost و sokanacademy به عنوان پارامتر ورودی در نظر می‌گیرد که بدین ترتیب کانکشنی با دیتابیس مد نظر روی لوکال‌هاست برقرار می‌شود که در آن نام کاربری و پسورد مربوط به لوکال‌هاست root در نظر گرفته شده و برای آرگومان آخر نیز گفته‌ایم که در هر بار برقراری کانکشن با دیتابیسی تحت عنوان sokanacademy دیتای مربوط به کانکشن برقرارشده در قالب کاراکترهایی با فرمت utf-8 به سرور ارسال شوند و در نهایت هم آبجکت مذکور از طریق this->conn$ به پراپرتی متناظرش منتسب می‌شود.

در تکمیل کلاس فوق، در ادامه هم فانکشنی تحت عنوان ()getConnection نوشته‌ایم که مشخصات مربوط به آبجکت ساخته‌شده از روی این کلاس (کانکشن برقرارشده با دیتابیس) و منتسب به پراپرتی conn$ را در خروجی ریترن می‌کند. حال جهت تست، فایل دیگری تحت عنوان index.php ساخته و کدهای زیر را در آن نوشته و اجرا می‌کنیم:

require_once 'ConnectDbWithoutSingleton.php';

$instance = new ConnectDbWithoutSingleton();
$conn = $instance->getConnection();
var_dump($conn);

$instance = new ConnectDbWithoutSingleton();
$conn = $instance->getConnection();
var_dump($conn);

$instance = new ConnectDbWithoutSingleton();
$conn = $instance->getConnection();
var_dump($conn);

 در کد فوق، ابتدا فایل مربوط به کلاس ConnectDbWithoutSingleton را ایمپورت کرده و در ادامه آبجکتی از این کلاس تحت عنوان instance$ ساخته‌ایم و بر اساس ساختار تعریف‌شده برای کانستراکتور، اکنون کانکشنی با دیتابیس sokanacademy برقرار شده و در ادامه فانکشن ()getConnection از این کلاس را روی آبجکت فوق فراخوانی کرده و نتیجۀ حاصل از اجرای آن را به پراپرتی conn$ منتسب می‌کنیم و در سطر بعد پراپرتی مذکور را به عنوان پارامتر ورودی به فانکشن ()var_dump می‌دهیم تا بدین ترتیب مشخصات مربوط به آبجکت ساخته‌شده (کانکشن برقرارشده با دیتابیس) در خروجی ریترن شود.

در سطر بعد نیز به همان ترتیب آبجکت دیگری از روی کلاس ConnectDbWithoutSingleton و مطابق با پروسۀ ساخت آبجکت اول می‌سازیم و برای بار سوم مجدداً آبجکت جدیدی از روی کلاس مذکور ساخته و مشخصات مربوط به کانکشن برقرارشده را با دستور ()var_dump در خروجی ریترن می‌کنیم که در نهایت نتیجۀ حاصل از اجرای کد فوق به صورت زیر خواهد بود:

object(PDO)#2 (0) { } object(PDO)#4 (0) { } object(PDO)#6 (0) { }

همان‌طور که می‌بینید، آرایه‌ای متشکل از سه آبجکت با یکسری اصطلاحاً Resource ID متفاوت داریم که در هر مرتبه آبجکتی جدید از روی کلاس ConnectDbWithoutSingleton ساخته شده است بدین معنی که در هر مرتبه کانکشنی مجزا با دیتابیس مذکور برقرار شده است که فرآیندی زمان‌بر بوده و منجر به کاهش سرعت وب اپلیکیشن می‌شود. در همین راستا و برای حل مشکل فوق، دیزاین پترن سینگلتون را در ادامه پیاده‌سازی می‌کنیم تا بدین وسیله ساخت آبجکت از روی کلاسی که مسئول ارتباط با دیتابیس است را مدیریت کنیم.

این بخش از محتوا مخصوص کاربرانی است که ثبت‌نام کرده‌اند.
جهت مشاهدهٔ این بخش از محتوا لاگین نمایید.

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

دانلود فایل‌های تمرین

لیست نظرات
کاربر میهمان
دیدگاه شما چیست؟
کاربر میهمان