آموزش برنامه نویسی

آموزش سی شارپ

آموزش سی شارپ

پربیننده ترین مطالب
پیوندهای روزانه

سلام به تمامی کاربران، با ادامه سری آموزشی زبان سی شارپ در خدمت شما عزیزان هستم. تا اینجا با کلیات برنامه نویسی شئ گرا و مفاهیم مرتبط با آن آشنا شدیم. در ادامه با بررسی مفهوم interface ها و کاربردهای آن، سعی خواهیم کرد دانش خود را در زمینه برنامه نویسی شئ گرا گسترش دهیم. مبحث interface ها، یکی از مهمترین مباحث در زمینه برنامه نویسی شئ گرا هستند و در صورت استفاده صحیح از آنها می توان کدهایی را نوشت که با کمترین هزینه، قابلیت نگهداری و توسعه را دارند.

تعریف interface ها


در حقیقت interface ها، به ما امکان تعریف مجموعه ای از خصوصیات و متدهای مرتبط را می دهند و قابلیت پیاده سازی در کلاس ها یا struct ها را دارند. با استفاده از interface ها، شما قابلیت پیاده سازی چندین ویژگی از چندین interface مختلف را در یک کلاس یا struct خواهید داشت. کلاس ها به صورت پیش فرض قابلیت ارث بری از چند کلاس را پشتیبانی نمی کنند و برای شبیه سازی این کار باید از interface ها استفاده کرد. در ابتدا با ساختار کلی تعریف interface آشنا می شویم:

{access-modifier} interface {name}
{
    {members}
}
  1. در قسمت access-modifier که سطح دسترسی به interface را مشخص می کنیم.
  2. در قسمت name، نام interface مشخص می شود. به این نکته توجه داشته باشید، استانداردی برای نام گذاری interface ها وجود دارد، به این صورت که در ابتدای نام interface بهتر است کاراکتر I قرار بگیرد تا کلاس ها و interface ها از یکدیگر مجزا شوند. برای مثال: IPerson یا IDatabaseManager.
  3. در قسمت member، باید اعضای interface را تعریف کنیم، دقت کنید که در این بخش برای اعضا نه می توان access-modifier مشخص کرد و نه بدنه ای برای متدها، تنها باید تعریف کلی از اعضاء نوشته شود و همچنین اعضای تعریف شده برای یک interface همگی به صورت پیش فرض سطح دسترسی public خواهند داشت.

با یک مثال ساده ادامه می دهیم. در نمونه کد زیر یک interface با نام INamed تعریف کردیم که یک خصوصیات به نام Name و یک متد با نام PrintName در آن تعریف شده است:

public interface INamed
{
    string Name { get; set; }

    void PrintName();
}

همانطور که در کد بالا مشاهده می کنید، سطح دسترسی نه برای خصوصیت مشخص شده و نه برای متد، همچنین متد ما بدنه نداشته و فقط حاوی signature می باشد. در ادامه قصد داریم تا از این interface استفاده کنیم. استفاده از interface دقیقاً مانند حالتی است که می خواهیم کلاس پدر را برای یک کلاس فرزند در وراثت مشخص کنیم:

public class Car : INamed
{
        
}

اما با نوشتن کد بالا پیغام خطا دریافت خواهید کرد. زیرا interface تنها حاوی تعریف کلی بوده و باید پیاده سازی در کلاسی که interface را به ارث برده انجام شود:

public class Car : INamed
{
    public string Name { get; set; }
    public void PrintName()
    {
        Console.WriteLine(Name);
    }
}

برای پیاده سازی خودکار interface، در صورتی که Resharper را نصب کرده باشید با بردن مکان نما بر روی نام کلاس، فشردن کلیدهای Alt+Enter و انتخاب گزینه Implement missing members عملیات پیاده سازی کلاس به صورت خودکار برای شما انجام می شود و در صورتی که Resharper نصب نباشد، با رفتن بر روی نام interface در مقابل کلاس و فشردن کلیدهای Ctrl+. عملیات پیاده سازی را می توانید انجام دهید.تا اینجا عملیات پیاده سازی کلاس را انجام دادیم، اما این پیاده سازی چه ویژگی هایی برای ما دارد و چگونه باید از interface استفاده کنیم؟ اگر توضیحات قسمت وراثت را به خاطر داشته باشید، گفتیم زمانی که یک کلاس، از کلاس دیگری ارث بری می کنید، می توان برای ساختن یک نمونه از کلاس، از نوع داده پدر استفاده کرد. این مورد، در باره interface ها هم صدق می کند، در حقیقت ما می توانیم از interface برای ایجاد شئ مورد نظر استفاده کنیم:

INamed namedInstance = new Car();

اما باید به یک نکته توجه داشته باشید، زمانی که از interface برای ساخت شئ استفاده می کنید تنها می توانید به اعضایی از کلاس دسترسی داشته باشید که در interface تعریف شده اند.یکی دیگر از قابلیت های interface، همانطور که در ابتدای این بخش گفته شد، امکان Multiple-Inheritance می باشد. به طور پیش فرض، شما تنها می توانید از یک کلاس در دات نت ارث بری کنید و امکان ارث بری از چند کلاس وجود ندارد. برای رفع این مشکل می توان از interface ها استفاده کرد. یعنی شما می توانید نام چند interface را در مقابل نام کلاس بنویسید. برای مثال، یک interface جدید با نام INotify تعریف می کنیم:

public interface INotify
{
    void Notify();
}

حال می توانیم در کلاس Car، علاوه بر INamed از INotify نیز استفاده کنیم:

public class Car : INamed, INotify
{
    public string Name { get; set; }
    public void PrintName()
    {
        Console.WriteLine(Name);
    }

    public void Notify()
    {
        Console.WriteLine("Notify me via Email!");
    }
}


پیاده سازی interface ها به صورت implicite و explicit


پیاده سازی interface ها در کلاس ها به دو صورت انجام می شود، implicite و explicit. تفاوت این دو روش در این است که در ابتدای نام عضو interface در کلاس، نام interface به همراه کاراکتر . قرار میگیرد. در قسمت های قبل، پیاده سازی ها بر اساس روش implicit انجام شد و در این قسمت با روش explicit آشنا می شویم. برای مثال فرض کنید می خواهیم INotify را به صورت explicit پیاده سازی کنیم، کد زیر پیاده سازی با این روش را نشان می دهد:

public class Car : INamed, INotify
{
    public string Name { get; set; }
    public void PrintName()
    {
        Console.WriteLine(Name);
    }

    void INotify.Notify()
    {
        Console.WriteLine("Notify me via Email!");
    }
}

اگر در کد بالا دقت کنید، برای متد Notify هیچ سطح دسترسی مشخص نشده است، زمانی که شما یک عضو را به صورت explicit پیاده سازی می کنید، هیچ سطح دسترسی نباید برای آن مشخص کنید. همچنین اعضایی که به صورت Explicit پیاده سازی می شوند تنها در صورتی قابل دسترس هستند که با نام interface از روی آنها شئ ساخته شود. یعنی در کد زیر شما به متد Notify دسترسی نخواهید داشت:

Car carInstance = new Car();
carInstance.Notify();

کد بالا منجر به پیغام خطا خواهد شد. اما کد زیر بدون مشکل اجرا می شود:

INotify notifyInstance = new Car();
notifyInstance.Notify();

یکی از مهمترین کاربردهای پیاده سازی explicit، امکان پیاده سازی چند interface با اعضای هم نام در یک کلاس است! برای روشتر شدن موضوع فرض کنید ما Interface ای داریم با نام IEmailNotify که عملیات اطلاع رسانی را به بوسیله ایمیل و interface دیگری داریم با نام ISMSNotify که عملیات اطلاع رسانی را بوسیله پیامک انجام می دهد. هر دوی این interface ها متدی دارند با نام Notify:

public interface IEmailNotify
{
    void Notify();
}

public interface ISMSNotify
{
    void Notify();
}

حال کلاس Car را به صورت زیر تغییر می دهیم:

public class Car : INamed, IEmailNotify, ISMSNotify
{
    public string Name { get; set; }
    public void PrintName()
    {
        Console.WriteLine(Name);
    }

    void IEmailNotify.Notify()
    {
        Console.WriteLine("Notify via Email!");
    }

    void ISMSNotify.Notify()
    {
        Console.WriteLine("Notify via SMS!");
    }
}

کد بالا دو پیاده سازی برای متد Notify دارد. یکی برای IEmailNotify و یکی برای ISMSNotify که بر اساس نوع داده مورد استفاده برای شئ، متد مربوطه فراخوانی خواهد شد. در ادامه کد زیر را در متد Main می نویسیم:

var car = new Car();

ISMSNotify smsNotify = car;
smsNotify.Notify();
IEmailNotify emailNotify = car;
emailNotify.Notify();

با اجرای کد بالا، ابتدا خروجی Notify via SMS و سپس Notify via Email در خروجی چاپ خواهد شد. ما در حقیقت یک شئ از نوع Car ایجاد کردیم و یکبار آن را داخل متغیری از نوع ISMSNotify قرار دادیم و بار دوم در متغیری با نام IEmailNotify. عملیات فراخوانی متد Notify به صورت خودکار بر اساس نوع متغیر انجام خواهد شد.مباحث مربوط به interface بسیار گسترده می باشد. یکی از مهمترین کاربردهای interface پیاده سازی IoC یا Inversion of Control و DI یا Dependency Injection در برنامه ها می باشد که در بخش بعدی با این تکنیک آشنا می شویم.

 منبع:programming.itpro.ir

  • متین تیماسی ، مبین خسروی و عمران جودکی

نظرات  (۰)

هیچ نظری هنوز ثبت نشده است
ارسال نظر آزاد است، اما اگر قبلا در بیان ثبت نام کرده اید می توانید ابتدا وارد شوید.
شما میتوانید از این تگهای html استفاده کنید:
<b> یا <strong>، <em> یا <i>، <u>، <strike> یا <s>، <sup>، <sub>، <blockquote>، <code>، <pre>، <hr>، <br>، <p>، <a href="" title="">، <span style="">، <div align="">
تجدید کد امنیتی