پیاده سازی چند ریختی با استفاده از interface

لغت interface یکی از پیچیده ترین و در عین حال بهترین ابزار جهت برنامه نویسی شی گراست. این کلمه نماینگر یکی از چهار رکن اصلی این نوع برنامه نویسی یعنی حالت چند ریختی است (Polymorphism).منظور از Interface یا protocol پایبندی به یک قرار داد از طرف کلاس است . یعنی کلاس تعهد می دهد که همواره از method و property های interface پیروی کند .syntax ایجاد interface در زبانهای برنامه نویسی متفاوت است . مثلا در php از interface و یا در swift از کلمه protocol استفاده می شود. پس مراحل را قدم به قدم و با زبان php به پیش می رویم .فرض کنید قصد داریم یک سیستم لاگر بنویسیم. خب تصمیم گیری می شود که این سیستم تمامی اطلاعات را داخل فایل قرار دهد ، پس : class LogToFile{ public function execute($message){ echo &quotSave to &quot . $message; } } کلاسی ایجاد کردیم با یک متد که وظیفه اش ذخیره سازی است ( برای کد کمتر این متد فقط یک پیغام چاپ می کند ).حالا فرض می کنیم یک کلاس ایجاد کردیم و می خواهیم هر وقت شی از این کلاس ساخته شد پیغام لاگ ذخیره شود . پس :class SMS { protected $logger; public function __construct(LogToFile $logger){ $this->logger=$logger; } public function sendSMS(){ echo “sending sms”; } }خوب همانطور که ملاحظه می کنید هر بار که یک شی جدید از این کلاس ایجاد شود به صورت اتوماتیک یک لاگ جدید بر روی فایل ایجاد می شودفرض کنیم که مدتی گذشت و مدیر سیستم خواست برای گرفتن گزارشات بهتر به جای ذخیره سازی لاگ ها بر روی فایل ، اطلاعات بر روی دیتا بیس ذخیره گردد.در اینجاست که مشکلات پیدا می شود . باید یک کلاس جدید ایجاد کنیم و متد execute را ایجاد کنیم و به جای کلاس LogToFile از کلاس جدیدی استفاده کنیم . این یعنی کلی جستجو و کلی عذاب و پیدا کردن تمام کلاس هایی که LogToFile رو در constructor استفاده کردند !!پس باید چیکار کرد؟؟قانون طلایی می گوید :بر روی interface برنامه نویسی کنید نه بر روی Implementationخب بگذارید این قانون طلایی را بر اساس کد باز کنیم:ابتدا یک interface ایجاد می کنیم:interface Logger{ public function execute($message); }همانطور که می بینید یک اینترفیس ایجاد کردیم که از لحاظ syntax مثل کلاس است. تنها با دو تفاوت :به جای واژه کلاس از interface استفاده کردیم.متد را تعریف کردیم و بدنه داخلی آنرا و اینکه چه کار را دقیقا باید انجام بدهد خالی گذاشتیم.حالا دو کلاس ایجاد می کنیم یکی برای ذخیره بر روی فایل و دیگری ذخیره بر روی دیتابیس با این تفاوت که در اینجا می گوییم که این کلاس حتما باید به interface ما یعنی logger متعهد باشدclass LogToFile implements Logger { public function execute($message){ echo &quotSave to &quot . $message; } } class LogToDatabase implements Logger { public function execute($message){ echo &quotSave to &quot . $message; } }خوب پس کلاس های ما متعهد شدند که متد execute را دارا باشند ولی اینکه این متد چه کاری را انجام دهد بسته به خود کلاس است.حالا در کلاس ها در قسمت construct به جای ساختن شی از کلاس LogToFile از interface که ساخته ایم استفاده می کنیم و به constructor می گوییم از هر کلاسی که به تعهد های این interface پایبند بود استفاده کن .class SMS{ protected $logger; public function __construct(Logger $logger){ $this->logger=$logger; } public function send SMS(){ echo “sending sms”; } }با این کار به کلاس این توانایی را میدهید که در جای مورد نیاز از LogToFile استفاده کنه:$sms=new SMS(new LogToFile);و در جای دیگری از LogToDatabase :$sms=new SMS(new LogToDatabase);پس یادمان باشد در جایی که امکان دارد تغییر و تحولاتی در کلاس ایجاد شود ( مثل لاگ یا خواندن از دیتابیس های مختلف و یا ...) از یک interface استفاده کنیم تا در آینده به مشکلات بر نخوریم .سعی کردم که با استفاده از یک مثال درک بهتری در رابطه با interface برای شما داشته باشم ولی زمان و مکان استفاده از آن در جاهای مختلف نیاز به تجربه زیاد دارد.