جشنواره فطر سون لرن

Interface چیست؟ آموزش مفهوم Interface در برنامه نویسی شی گرا با مثال عملی

دسته بندی: برنامه نویسی
سطح مقاله: متوسط
زمان مطالعه: 8 دقیقه
۲۲ آبان ۱۳۹۸
فارسی
اینترفیس
English
Interface

در برنامه نویسی تیمی گاهی نیاز می‌شود هر عضو گروه، یک کلاس از نوعی خاص را پیاده‌سازی کند که معمولا هر برنامه نویس استاندارد خاص خود را برای نام‌گذاری توابع و متغیر‌های کلاس دارد. این روند باعث ایجاد به‌هم‌ریختگی و ناخوانایی در کدها می‌شود. برای جلوگیری از ایجاد این مشکل در برنامه نویسی شی گرا (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) دریافت می‌کنیم و برنامه متوقف می‌شود.

یک مثال کاربردی از Interface

بهترین روش پیاده‌سازی اتصال به پایگاه داده در هر برنامه روشی است که وابسته به نوع پایگاه داده و نوع پیاده‌سازی اتصال به آن نباشد. با این جملات احتمالا به راحتی متوجه به اهمیت و کاربرد اینترفیس در این مثال شده‌اید. در این مثال با استفاده از اینترفیس تمام پیاده‌کننده‌ها یا درایور‌های پایگاه داده مثل 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 نیز یکی از مباحث ابتدایی و مهم در یادگیری برنامه نویسی شی گرا است که امیدواریم به شما در فهم آن کمک کرده باشیم. افراد زیادی به دلایل مختلفی مانند علاقمندی یا کسب درآمد از طریق برنامه نویسی به دنبال یادگیری زبان‌های مختلف هستند. فراموش نکنید سون لرن در مسیر یادگیری برنامه نویسی همواره در کنار شما است.

چه امتیازی به این مقاله می دید؟
نویسنده زهرا فرحمند

نظرات کاربران

محمد رحمتی

بسیا عالی ممنون از زحمت شما. سپاس

فرانک خوابستان

خیلی مفید بود ممنون از شما

ریحانه یزدانی

سلام
ممنون از شما برای وقتی که گذاشتین 🙂

ایلیا

پیاده سازی پایگاه داده اخرش چه جالب بود
نمیشه کاری کرد که کلاس DatabaseConsumer خودش شی از کلاس درایور بسازه و کارا اتوماتیک شه؟

زهرا فرحمند

سلام ایلیای عزیز.
کلاس DatabaseConsumer رو برای رسیدن به اصل OpenClosed در سالید نوشتیم پس دستکاری کلاس برای تغییر درایور از دیدگاه سالید غیر قانونیه. پس به هر حال درایور باید از بیرون کلاس بهش پاس داده بشه. اگر با اصول SOLID آشنا نیستید می تونید مقالات بعدی در این مورد رو مطالعه کنید. ممنونم از توجهتون 🙂

امیرحسین ضیایی

مرسی از مقالتون

زهرا فرحمند

مرسی از همراهی شما آقای ضیایی عزیز 🙂

امیر حسین عزیزیان

خیلی مهمه که درباره یه موضوع ، مفهوم ، مسئله یا هر چیزی که اسمشو میذارید تر و تمیز توضیح داده بشه . ب نظرم این مطلب این ویژگی رو داشت

زهرا فرحمند

سلام خوشحالم که استفاده کردید 🙂

ارسال دیدگاه
خوشحال میشیم دیدگاه و یا تجربیات خودتون رو با ما در میون بذارید :