همانطور که گفته شد الگوی طراحی سینگلتون از زیر دسته ی creational میباشد یعنی ما یک مسئله برای ساخت objectها داریم که میخواهیم با این الگو طراحی کنیم.
معنای کلمه سینگلتون، یکی بودن است یعنی مشخص است objectای که با استفاده از این الگو طراحی میشود توی کل پروژه یبار ساخته شده است.
سوالی که پیش می آید چرا باید فقط یک object از یک کلاس را داشته باشیم؟ بجاش میتونیم یه کلاس با متدهای استاتیک داشته باشیم. جوابی که وجود دارد این که گاهی واقعا نیاز نیست که صدتا objساخته شود و در کل پروژه یک شی از آن کلاس کافیه.
مثلا میخواهیم اتفاقاتی که در کل پروژه میفتد را لاگ بگیریم. برای اینکار یک شی بلاگر کافی است و لزومی ندارد که چندبار new کنیم. البته باید توجه داشت هر بار ساخت شی با new بار هزینه ای زیادی برای برنامه دارد که با این الگو میتوانیم کاهش دهیم.
البته که usecase های مختلفی دارد و فقط اون یه مثال ساده بود.
بعنوان مثال apiهایی که بازای هربار استفاده مبلغ پولی را شارژ میکنند. یا استفاده از یک پلاگین وردپرسی در پروژه، کافیه یکبار new کند و از امکانات اون کلاس استفاده کند.
حال در عمل چگونه سینگلتون پیاده سازی میشود؟ البته که دیزاین پترن ها فارغ از زبان هستند اما برای پیاده سازی به یک زبان نیاز است که من زبان php را انتخاب کردم.
1- ابتدا یک private constructor برای جلوگیری از ساخت مستقیم شی از کلاس تعریف میشود.
2- تنها راه ساخت فقط یک شی از کلاس استفاده از متد استاتیک است که قبلا درست نشده باشد.
//general singleton class class singleton { //تعریف متغیر برای نگهداری نمونه کلاس سینگلتون private static $instance = null; // تعریف کانستراکتور بصورت پرایویت // to prevent initiation with outer code. private function __construct() { // The expensive process (e.g.,db connection) goes here. } // اگر کلاس هیچ شی ای نداشت بسازد در غیر اینصورت برگرداند. public static function getInstance() { if (self::$instance == null) { self::$instance = new Singleton(); } return self::$instance; } }
حال برای فراخوانی آن میتوان بصورت زیر عمل کرد:
// All the variables point to the same object. $object1 = Singleton::getInstance(); // ابتدا شی در اینجا ساخته میشود $object2 = Singleton::getInstance(); // در اینجا شی ساخته شد گرفته میشود. $object3 = Singleton::getInstance();
حال اگر بخواهیم یه مثال کاربردی تر بزنیم میتوانیم اتصال به دیتابیس را مطرح کنیم.
class ConnectDb { private static $instance = null; private $conn; private $host = 'localhost'; private $user = 'db user-name'; private $pass = 'db password'; private $name = 'db name'; // The db connection is established in the private constructor. private function __construct() { $this->conn = new PDO("mysql:host={$this->host}; dbname={$this->name}", $this->user,$this->pass, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'")); } public static function getInstance() { if(!self::$instance) { //اگر وجود نداشت و یا نمونه ای براش ساخته نشده بود self::$instance = new ConnectDb(); //کانستراکتور را براش اجرا میکند و ایجاد میشود. } return self::$instance; } public function getConnection() { return $this->conn; } }
تا زمانیکه ما از این کلاس برای چک کردن کانکشن استفاده میکنیم، مهم نیست چندبار شی را خارج از کلاس میسازیم. چون در هربار اجرا فقط یک شی دارد. برای اثبات حرفمون کافیه کدهای زیر اجرا شود.
$instance = ConnectDb::getInstance(); $conn = $instance->getConnection(); var_dump($conn); $instance = ConnectDb::getInstance(); $conn = $instance->getConnection(); var_dump($conn); $instance = ConnectDb::getInstance(); $conn = $instance->getConnection(); var_dump($conn);
همانطور که خواهیم دید هر سه شی، مقدار یکسانی را برمیگرداند.
در مقاله بعدی به بررسی دیزاین پترن فکتوری میپردازم.
منبع: اینترنت و سون لرن