بررسی اینترفیس (Interface) ها در زبان برنامه نویسی سی شارپ

بررسی اینترفیس (Interface) ها در زبان برنامه نویسی سی شارپ

در این پست از وبسایت پرووید، در رابطه با بررسی اینترفیس (Interface) ها در زبان برنامه نویسی سی شارپ صحبت خواهیم کرد. به ادامه ی مطلب بروید.

در این قسمت از این سری آموزشی از وب سایت پرووید در رابطه با اینترفیس ها در زبان برنامه نویسی سی شارپ صحبت خواهیم کرد. در ابتدای کار توصیه می کنیم که برای درک هرچه بهتر مفهوم Interface ها در زبان سی شارپ از بسته ی آموزش ویدئویی اینترفیس ها در سی شارپ استفاده کنید.

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

در زبان برنامه نویسی سی شارپ یک کلاس و یا یک Struct می‌تواند یک و یا چند Interface را پیاده سازی کند. در زبان سی شارپ یک Interface را می توانیم با کلمه کلیدی interface ایجاد کنیم. Interface ها می توانند شامل تعاریف متدها، Property ها، Indexer ها و Event ها باشند. در رابطه با ماهیت مربوط به Property ها و متدها و همچنین Indexer ها در قسمت‌های دیگر مربوط به این سری آموزشی صحبت خواهیم کرد. حال مثالی ساده از نحوه تعریف کردن یک Interface با نام IPen را در قسمت زیر مشاهده می کنید.

interface IPen
{
    string Color { get; set; }
    bool Open();
    bool Close();
    void Write(string text);
}

 همانطور که در این Interface می بینید یک Property به نام Color از نوع String تعریف شده است و همچنین دو متد با نام‌های Open و Close که Boolean را به عنوان خروجی Return می‌کنند. علاوه بر این یک متد دیگر به نام Write تعریف شده است که به عنوان ورودی یک پارامتر از نوع String را دریافت کرده و Void را بر می گرداند. یکی از نکات مربوط به استفاده کردن از Interface ها در زبان سی شارپ این است که شما نمی توانید از Access Modifier ها برای اعضای تعریف شده در یک Interface استفاده کنید. تمامی اعضای تعریف شده در یک Interface به صورت پیش فرض از نوع Public هستند. اگر در یک Interface یک Access Modifier را استفاده کنید Compiler زبان سی شارپ یک خطا ایجاد خواهد کرد. کدی که در قسمت زیر مشاهده می کنید مثالی در رابطه با همین موضوع است.

interface IPen
{
    public string Color { get; set; }  //error
    protected bool Open(); //error
    private bool Close();  //error
    protected internal void Write(string text);//error
}

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

interface IPen
{
    string Color { get; set; }
    bool Open();
    bool Close();
    void Write(string text){
        Console.Write(text);  //error: cannot implement method
    }
}

 پیاده سازی یک Interface

طبیعتاً بعد از تعریف کردن یک Interface باید آن را در یک کلاس و یا Struct پیاده سازی کنیم. برای استفاده کردن از یک Interface و پیاده سازی آن شبیه به کدی که در قسمت زیر مشاهده می کنید عمل خواهیم کرد.

class Cello : IPen
{
    public string Color { get; set; }
        
    private bool isOpen = false;
        
    public bool Close()
    {
        isOpen = false;
        Console.WriteLine("Cello closed for writing!");

        return isOpen;
    }

    public bool Open()
    {
        isOpen = true;
        Console.WriteLine("Cello open for writing!");
            
        return isOpen;
    }

    public void Write(string text)
    {
        //write text if open
        if(isOpen)
            Console.WriteLine("Cello: " + text);
    }
}

 همان طور که در این مثال می بینید یک کلاس با نام Cello  اینترفیس IPen را پیاده سازی کرده است. ضمناً تمامی اعضای مربوط به اینترفیس IPen با استفاده از Access Modifier  لحاظ شده یعنی Public در این کلاس تعریف می گردد. علاوه بر این دیگر اعضای کلاس Cello که از اینترفیس IPen وارد این کلاس نشده اند می توانند Access Modifier های مختلف داشته باشند. برای مثال IsOpen یک Field است که به صورت Private تعریف شده است. بنابراین باید بدانید که تمامی اعضای درون یک Interface باید با Access Modifier پیش فرض Public تعریف بشوند و سی شارپ در صورت استفاده کردن از هر Access Modifier دیگری خطا ایجاد خواهد کرد.

 پیاده سازی صریح یک Interface و یا Explicit Implementation

پیاده‌سازی صریح و یا Explicit Implementation زمانی اتفاق می‌افتد که یک کلاس می‌خواهد چندین Interface را پیاده سازی کند و برای افزایش قابلیت خوانایی و جلوگیری از سردرگمی برنامه‌ نویس نام Interface مورد نظر را در کنار نام اعضای آنها قرار می‌دهند. در رابطه با افزایش قابلیت خوانایی از بسته ی آموزش ویدئویی اصول کدنویسی با کیفیت بالا استفاده کنید. لطفاً دقت کنید که در Explicit Implementation نیز نباید از Public استفاده کرد. برای پیاده سازی یک Interface به صورت صریح و یا همان Explicit Implementation نام Interface مورد نظر را به عنوان پیشوند اعضای آن Interface لحاظ می‌کنیم. این موضوع در کد زیر نشان داده شده است.

class Cello : IPen
{
    string IPen.Color { get; set; }
        
    private bool isOpen = false;
        
    bool IPen.Close()
    {
        isOpen = false;
        Console.WriteLine("Cello closed for writing!");

        return isOpen;
    }

    bool IPen.Open()
    {
        isOpen = true;
        Console.WriteLine("Cello open for writing!");
            
        return isOpen;
    }

    void IPen.Write(string text)
    {
        //write text if open
        if(isOpen)
            Console.WriteLine("Cello: " + text);
    }
}

 همانطور که در مثال بالا مشاهده می کنید Explicit Implementation برای Interface مورد نظر در نظر گرفته شده است. لطفاً دقت کنید که استفاده کردن از Public در استفاده از این روش امکان پذیر نیست و اگر از این کلمه استفاده کنید خطا ایجاد خواهد شد. لطفا دقت کنید که یک Interface می‌تواند توسط کلاس های مختلف پیاده سازی شود؛ بنابراین کلاس زیر که Parker نام دارد اقدام به پیاده سازی اینترفیس IPen کرده است.

class Parker : IPen
{
    public string Color { get; set; }
        
    private bool canWrite = false;
        
    public bool Close()
    {
        canWrite = false;
        Console.WriteLine("Parker is closed now!");

        return canWrite;
    }

    public bool Open()
    {
        canWrite = true;
        Console.WriteLine("Parker is open now!");
            
        return canWrite;
    }

    public void Write(string text)
    {
        //write text if open
        if(canWrite)
            Console.WriteLine("Parker: " + text);
    }
}

همانطور که در این مثال می بینید کلاس Parker، اینترفیس IPen را پیاده سازی کرده است. بنابراین تمامی اعضای تعریف شده در اینترفیس IPen باید در کلاس Parker تعریف بشود. البته این کار نسبت به پیاده سازی موجود در کلاس Cello متفاوت است. به عبارت دیگر بدنه متدهای Open و Close و Write پیام های مختلفی را چاپ خواهند کرد. از این موضوع می توان این را نتیجه گرفت که کلاس ها و Struct های مختلف می‌توانند یک Interface یکسان را پیاده سازی کرده اما برای متدهای آن Interface یکسان، پیاده سازی های مختلفی را در نظر بگیرند. موضوع دیگر این که در تعریف کردن اشیا و یا Object از یک کلاس می توان نوع متغیر مورد نظر را با Interface که توسط آن کلاس پیاده سازی شده است تنظیم کرد. این موضوع در کد زیر نشان داده شده است.

IPen pen1 = new Cello();

IPen pen2 = new Parker();

در این مثال مشاهده می‌کنیم که از آنجایی که کلاس Cello و Parker اینترفیس IPen را پیاده سازی کرده اند می توان از Interface مورد نظر برای تعریف متغیر هایی که به اشیایی از این دو کلاس اشاره می‌کنند استفاده کرد. علاوه بر این از یک متغیر یکسان که از این Interface ساخته شده است می توان اشیای مختلفی از کلاس های مختلف که همین Interface را پیاده سازی می کنند ایجاد کرد. برای مثال در کد زیر متغیر MyPen که از نوع اینترفیس IPen  است یکبار به یک Object از کلاس Cello و بار دیگر به یک Object از کلاس Parker اشاره می‌کند.

IPen mypen = new Cello();
mypen = new Parker();

پیاده‌سازی چندین Interface

همانطور که قبلاً نیز گفتیم یک کلاس و یا Struct می تواند چندین Interface را پیاده سازی کرده و به این منظور باید تمامی اعضای درون تمامی آن Interface ها را در درون خود جای بدهد. مثالی که در قسمت زیر مشاهده می‌کنید این موضوع را نشان می دهد.

interface IBrandedPen
{
    string GetBrandName();
}

class Parker : IPen, IBrandedPen
{
    //Implement all members of IPen and IBrandedPen
}

حال کلاس Parker می‌تواند با استفاده از یا اینترفیس IPen  و یا اینترفیس IBrandedPen یک Object از آن ساخته شود. کدی که در قسمت زیر مشاهده می‌کنید این موضوع را نشان می دهد.

IPen pen1 = new Parker();
pen1.Open();// valid 
pen1.GetBrandName(); //Compile-time error. Cannot call IBrandedPen method on the object of type IPen

IBrandedPen pen2 = new Parker();
pen2.GetBrandName();// valid 
pen2.Open();//Compile-time error. Cannot call IPen method on the object of type IBrandedPen

 همانطور که در قسمت بالا مشاهده می کنید Object ساخته شده از این Interface ها فقط و فقط متدهایی را پشتیبانی می‌کنند که توسط آن Interface ها تعریف شده است؛ به عبارت دیگر در مثال بالا متغیر pen1 فقط می‌تواند از متدهایی استفاده کند که در اینترفیس IPen  وجود دارند و متغیر pen2 فقط از متدهایی می‌تواند استفاده کند که در اینترفیس IBrandedPen وجود دارد. موضوع بعدی این که Interface ها می توانند در وراثت شرکت کنند و از یکدیگر ارث بری نمایند. این کار دقیقاً شبیه به کلاس ها انجام می‌شود. نحوه انجام این کار در قالب یک مثال در قسمت زیر نشان داده شده است.

interface IPen
{
    string Color { get; set; }
    bool Open();
    bool Close();
    void Write(string text);
}

interface IBrandedPen : IPen 
{
    string GetBrandName();
}

class Parker : IBrandedPen
{
    //Implement all members of IPen and IBrandedPen
}

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

مرتضی گیتی
بدون نظر

ارسال نظر

نظر
نام
ایمیل
وب سایت