در برنامه نویسی تیمی گاهی نیاز میشود هر عضو گروه، یک کلاس از نوعی خاص را پیادهسازی کند که معمولا هر برنامه نویس استاندارد خاص خود را برای نامگذاری توابع و متغیرهای کلاس دارد. این روند باعث ایجاد بههمریختگی و ناخوانایی در کدها میشود. برای جلوگیری از ایجاد این مشکل در برنامه نویسی شی گرا (Object-Oriented) مفهومی به نام Interface به وجود آمده است که در ادامه قصد توضیح آن را داریم.
interface چیست
اینترفیس (Interface) مفهومی مشابه کلاس است با این تفاوت که نمیتوان در آن متدی را پیادهسازی کرد. در واقع اینترفیس فقط مجموعهای از قراردادها (contract) است که متدهای مختلف بدون تعریف بدنه (Body) و عملکرد در آن تعریف شده اند و کلاسی که این اینترفیس را پیادهسازی میکند، باید درون خود از آن تابع استفاده کرده و برای آن عملکرد تعریف کند. فراموش نکنید که هر کلاس میتواند بیشتر از یک اینترفیس را پیادهسازی کند. به عنوان مثال در کد PHP زیر یک اینترفیس به نام شکل یا Shape را پیاده سازی کرده ایم:
interface Shape { public function getArea(); }
این به آن معنی است که از این پس هر کلاسی که اینترفیس Shape را پیادهسازی کند ملزم به پیادهسازی متد getArea() در خود است. در کد زیر دو کلاس Square یا مربع و Rectangle یا مستطیل اینترفیس Shape را پیاده کردهاند:
class Square implements Shape { private $width; public function __construct($width) { $this->width = $width; } public function getArea() { return $this->width * $this->width; } }
class Rectangle implements Shape { private $width; private $height; public function __construct($width , $height) { $this->width = $width; $this->height = $height; } public function getArea() { return $this->width * $this->height; } }
ممکن است این سوال برایتان پیش بیاید که چرا در این مثال از Interface استفاده کردیم در حالی که میتوانستیم به راحتی کلاسی به نام Shape داشته باشیم که طول و عرض هر شکل را در سازنده یا Constructor خود دریافت کرده و سپس در متد getArea() پیادهسازی کند. در این حالت کافی بود بقیه کلاسها از آن به ارث ببرند و بر اساس قانون وراثت صاحب تمام متدها و ویژگیهای Shape شوند. در آن صورت کلاس Shape و کلاسهای فرزند آن به این شکل نوشته میشد:
class Shape { private $width; private $height; public function __construct($width , $height) { $this->width = $width; $this->height = $height; } public function getArea() { return $this->width * $this->height; } }
فرض کنید میخواهیم کلاسی به نام Circle یا دایره را در مجموعه کلاسهای اشکال خود داشته باشیم. همانطور که میدانید مساحت دایره برخلاف مستطیل و مربع بر اساس طول و عرض نیست بلکه بر اساس شعاع آن است. درحالیکه متد getArea() در کلاس والد آن یعنی Shape بر اساس طول و عرض پیادهسازی شده است! بنابراین میبینید که بهترین گزینه برای این مثال استفاده از اینترفیس بوده است. با استفاده از اینترفیس کلاس Circle به راحتی به صورت زیر پیاده میشود:
class Circle implements Shape { private $radius; public function __construct($radius) { $this->radius = $radius; } public function getArea() { return $this->radius * (3.14 ** 2); } } $circle = new Circle(2); echo $circle->getArea();
پس از پیادهسازی اینترفیس Shape در صورتی که تمام متدهای آن را در کلاسی که از این اینترفیس استفاده کرده، پیادهسازی نکنیم، یک خطای مهلک (Fatal Error) دریافت میکنیم و برنامه متوقف میشود.
بهترین روش پیادهسازی اتصال به پایگاه داده در هر برنامه روشی است که وابسته به نوع پایگاه داده و نوع پیادهسازی اتصال به آن نباشد. با این جملات احتمالا به راحتی متوجه به اهمیت و کاربرد اینترفیس در این مثال شدهاید. در این مثال با استفاده از اینترفیس تمام پیادهکنندهها یا درایورهای پایگاه داده مثل mySQL و SQLServer را ملزم به داشتن متدهای connect و query میکنیم. در واقع با استفاده از اینترفیس در این نمونه دیگر فرقی نمیکند که بعدها از چه روشی برای اتصال به پایگاهداده استفاده میشود. روش دسترسی به دادهها همیشه یکی است!
interface SQLDriver { public function connect(); public function query($query); } class MySQL implements SQLDriver { public function connect() { // connecting to a mysql database } public function query($query) { echo $query; // query to a mysql database } } class SQLServer implements SQLDriver { public function connect() { // connecting to a sqlServer database } public function query($query) { // query to a sqlServer database } }
حال برای استفاده از پایگاه داده کافی است یک کلاس واسط مثلDatabaseConsumer داشته باشیم و شی درایور پایگاه داده مورد نظر خود را به آن پاس دهیم تا همه چیز به صورت اتوماتیک انجام شود:
class DatabaseConsumer { private $provider; public function __construct(SQLDriver $sqlDriver) { $this->provider = $sqlDriver; $this->provider->connect(); } public function query($query) { $this->provider->query($query); } } $dc = new DatabaseConsumer(new MySQL()); $dc->query("SELECT * FROM `posts`");
در مثال بالا در متد سازنده یا __construct() شی SQLDriver که در واقع همان شی درایور پاس داده شده به DatabaseConsumer است، در اتریبیوت provider این کلاس ذخیره میشود. با این کار از این پس به تمام متدهای public درایور مورد نظر دسترسی داریم.
حال کافی است برای راهاندازی پایگاه داده در متد سازنده با استفاده از متد connect درایور مورد نظر، به آن متصل شویم. سایر متدهای کلاس واسط نیز با اتصال به متدهای متناسب در کلاس درایور داده شده، عمل درخواست شده را انجام میدهند. حال در خارج از کلاس، برای استفاده از پایگاه داده کافی است یک شی از کلاس درایور مورد نظر را ایجاد کرده و به سازنده کلاس DatabaseConsumer پاس دهیم.
همچون وراثت، مفهوم Interface نیز یکی از مباحث ابتدایی و مهم در یادگیری برنامه نویسی شی گرا است که امیدواریم به شما در فهم آن کمک کرده باشیم. افراد زیادی به دلایل مختلفی مانند علاقمندی یا کسب درآمد از طریق برنامه نویسی به دنبال یادگیری زبانهای مختلف هستند. فراموش نکنید سون لرن در مسیر یادگیری برنامه نویسی همواره در کنار شما است.