کانال بله, جهت پشتیبانی و اطلاع رسانی کانال بله, جهت پشتیبانی و اطلاع رسانی
عضویت

آموزش کار با Interface ها در C#

وقتی توی C# با کلاس‌ها و شیءها کار می‌کنی، ممکنه به جایی برسی که لازم باشه مشخص کنی کلاس‌های مختلف چه رفتارها و قابلیت‌هایی باید داشته باشن. اینجاست که Interfaceها وارد ماجرا می‌شن و کمک می‌کنن یک چارچوب مشخص برای پیاده‌سازی کلاس‌ها داشته باشیم.

در این آموزش، با مفهوم Interface در C# و نحوه استفاده از اون آشنا می‌شیم. اگه توی مسیر یادگیری C# هستی، شناخت Interfaceها می‌تونه درک بهتری از نحوه طراحی و ساختاردهی کد در اختیارت قرار بده.

در درس قبل، درباره کلاس‌های پایه یا Abstractها در C# صحبت کردیم. Interfaceها در C# هم تا حد زیادی شبیه Abstract Classها هستن و از این نظر که نمی‌تونیم از روی اون‌ها یک نسخه یا شیء بسازیم، با هم شباهت دارن.
با این حال، Interfaceها حتی از کلاس‌های Abstract هم مفهومی‌تر هستن؛ چون بدنه دستورات متد (method body) در اون‌ها اصلاً مجاز نیست. یعنی نمی‌تونیم برای متدهایی که تعریف می‌کنیم، دستوری مشخص کنیم. از اونجایی که در Interfaceها متدی با کد واقعی وجود نداره، بنابراین به فیلدها (Fields) هم نیازی نیست. با این حال، تعریف خواص (Properties)، اندیس‌ها (indexer) و رویدادها (event) امکان‌پذیره.
می‌تونی یک Interface رو مثل یک Contract (قرارداد) در نظر بگیری؛ یعنی کلاسی که اجرای اون مستلزم اینه که تمام متدها (methods) و خواص (Properties) تعریف‌شده در Interface رو پیاده‌سازی کنه.

نکته :

نکته مهم درباره Interfaceها اینه که C# از ارث‌بری چندگانه (multiple inheritance) پشتیبانی نمی‌کنه؛ یعنی یک کلاس نمی‌تونه از بیشتر از یک کلاس پایه به ارث بره. با این حال، می‌تونه از چند Interface مختلف استفاده کنه.


اما تمام این مواردی که گفتیم، در کد چطور نوشته می‌شن؟ کد مثال زیر نمونه خوبی از استفاده از Interfaceها در C# هست. به این مثال دقت کن؛ در ادامه توضیح می‌دیم هر بخش از کد چه کاری انجام می‌ده.

using System;
using System.Collections.Generic;

namespace Interfaces
{
    class Program
    {
        static void Main(string[] args)
        {
            List dogs = new List();
            dogs.Add(new Dog("Fido"));
            dogs.Add(new Dog("Bob"));
            dogs.Add(new Dog("Adam"));
            dogs.Sort();
            foreach(Dog dog in dogs)
                Console.WriteLine(dog.Describe());
            Console.ReadKey();
        }
    }

    interface IAnimal
    {
        string Describe();

        string Name
        {
            get;
            set;
        }
    }

    class Dog : IAnimal, IComparable
    {
        private string name;

        public Dog(string name)
        {
            this.Name = name;
        }

        public string Describe()
        {
            return "Hello, I'm a dog and my name is " + this.Name;
        }

        public int CompareTo(object obj)
        {
            if(obj is IAnimal)
                return this.Name.CompareTo((obj as IAnimal).Name);
            return 0;
        }

        public string Name
        {
            get { return name; }
            set { name = value; }
        }
    }
}
        

بیایید از بخش میانی کد، یعنی جایی که Interface رو تعریف کردیم، شروع کنیم. همون‌طور که می‌بینی، تنها تفاوت در تعریف یک Interface به جای Class، کلمه کلیدی‌ایه که استفاده می‌کنیم؛ اینجا به جای class از interface استفاده شده. همچنین قبل از نام Interface یک I قرار دادیم تا مشخص بشه با یک Interface روبه‌رو هستیم. این کار فقط یک استاندارد کدنویسیه و اجباری نیست. می‌تونی Interface موردنظرت رو هر جای برنامه که بخوای استفاده کنی و از اونجایی که نحوه استفاده از اون‌ها شبیه کلاس‌هاست، قرار دادن I قبل از نام Interface باعث می‌شه کد برای کدنویس راحت‌تر قابل تشخیص و درک باشه.
بعد از اون، متد Describe رو تعریف کردیم و سپس خاصیت Name یا Property رو نوشتیم که هر دو واژه کلیدی get و set رو داره. این یعنی این خاصیت هم قابلیت خواندن داره و هم می‌شه مقدارش رو تغییر داد.

نکته :

همون‌طور که متوجه شدی، خواص تعیین‌کننده میدان دید یا سطح دسترسی (access modifiers) مثل public، private، protected و ... در ابتدای نام Interface قرار نگرفتن. دلیلش اینه که این خواص در Interfaceها مجاز نیستن و همه اون‌ها به صورت پیش‌فرض public هستن.


در مرحله بعد، کلاس Dog class رو داریم. با قرار دادن یک : بین نام کلاس و Interface موردنظر، مشخص کردیم که کلاس Dog از Interface استفاده می‌کنه. این کار از نظر نوشتاری شبیه ارث‌بری بین کلاس‌هاست. اما در کد بالا دو Interface رو برای کلاس Dog به کار بردیم و اون‌ها رو با کاما (،) از هم جدا کردیم. می‌تونی هر تعداد Interface که بخوای در مقابل نام کلاس تعریف کنی، اما در این مثال فقط دو Interface با نام‌های IAnimal و IComparable رو به کلاس خودمون نسبت دادیم. IComparable یک Interface مشترک بین کلاس‌هایی هست که قابلیت مرتب شدن (sorting) دارن. بنابراین، در کد بالا هم یک method و یک property رو از IAnimal Interface استفاده کردیم و هم‌زمان متد CompareTo رو از IComparable interface به کار بردیم.
حالا ممکنه با خودت فکر کنی اگه قراره همه کارها رو خودمون انجام بدیم و تمام متدها و خواص Properties لازم رو در کد تعریف کنیم، چرا باید برای نوشتن Interface این‌قدر زحمت بکشیم؟
جواب این سؤال رو می‌تونیم در بخش بالایی کد مثال ببینیم و متوجه بشیم که چرا صرف این زمان ارزشمنده.
در مثال بالا، چند Dog رو به عنوان objectهای یک list تعریف کردیم و بعد لیستمون رو مرتب یا sort کردیم. اما List از کجا می‌دونه که چطور باید نام سگ‌ها رو مرتب کنه؟ دلیلش اینه که کلاس Dog Class متدی به نام CompareTo داره که مشخص می‌کنه دو Dog چطور باید با هم مقایسه بشن.
اما List چطور متوجه می‌شه که شیء Dog object می‌تونه عمل مرتب‌سازی رو انجام بده و باید کدوم متد رو برای مقایسه سگ‌ها فراخوانی کنه؟ دلیلش اینه که با تعیین یک Interface مناسب و نسبت دادن اون به کلاس، این موضوع رو به List اعلام کردیم. Interface باید متد CompareTo رو اجرا کنه و همین موضوع یکی از نکات مهم استفاده از Interfaceها در کده.

اگه می‌خوای این مفاهیم رو در کنار سایر مباحث مهم زبان C# به شکل منظم و اصولی یاد بگیری، می‌تونی مسیر یادگیریت رو با دوره آموزش C# ادامه بدی و مباحث برنامه‌نویسی با C# رو قدم‌به‌قدم دنبال کنی.

1405/06/11 33755 2894
رمز عبور : tahlildadeh.com یا www.tahlildadeh.com
نظرات شما

نظرات خود را ثبت کنید...