وبسایت شخصی حسن هاشمی

برنامه نویس. ایران. قم :))

کاربرد Inteface ها در #C

چند روز پیش یه ایمیل از ایمان عزیز دریافت کردم، ایشون از من خواسته بودن در مورد کاربرد interface و delegate در سی شارپ توضیح بدم.

و مخصوصاً اینکه چجوری این دوتا باعث میشن کد ما راحت تر به روزرسانی بشه. خب امروز هم که جمعه هست و با خودم گفتم بیا یه نفعی به بشریت برسونیم :)

کلید این سوال توی مفهوم وراثت نهفته هست. و اون هم اینه که یه متغیر از نوع interface میتونه با یه instance از نوع کلاسی که اون رو پیاده سازی کرده مقداردهی بشه.

کاربرد اینترفیس در برنامه نویسی امروزی خیلی خیلی زیاده و شاید خودم 99 درصد مواقع وقتی یه پروژه ای رو تازه شروع می کنم اولین خط کدی که می نویسم یه اینترفیس هست.

بذارید این رو با یه مثال کاربردی تر توضیح بدم

فقط دو تا چیز اونم اینکه برای این فهم این مطلب شما باید یه آشنایی اجمالی با اینترفیس داشته باشید و دوم هم کدهایی که تو این مثال میذارم فقط برای مثال هستن و اصلاً بدرد کار واقعی نمی خورن :)

چند روز پیش توی یه پروژه ای که شبیه شبکه های اجتماعی بود و ما نوشتیمش؛ تبلیغات همیشه بر اساس تگ های انتخابی کاربر موقع ثبت نام بهش نمایش داده میشه، فرض کنیم کلاس UserController وظیفه نمایش رو بر عهده داره:

  1. public class UserController
  2. {
  3. private Database _db = new Database();
  4. // اینم متد تبلیغات رو نشون میده به کاربر
  5. public void ShowAds()
  6. {
  7. //// دریافت بر حسب تگ
  8. foreach (var item in _db.Ads.GetByTag())
  9. {
  10. // نمایش تبلیغات
  11. }
  12. }
  13. }

 اما حالا از ما خواسته شده تا بعضی وقتها بر حسب تگ و بعضی وقتها هم توسط هوش مصنوعی تبلیغات از توی دیتابیس انتخاب بشه.

خب؟ حالا چی کار باید بکنیم؟ 

اینکه ما دو تا منبع تأمین کننده تبلیغات برای کاربر داریم تا اینجا روشنه، اما اینکه هر بار بخوایم بین هوش مصنوعی و سیستم تگ گذاری جابجا بشینیم همه جاهایی که تو برنامه از تبلیغات استفاده شده رو تغییر بدیم خیلی افتضاحه :)

کاری که ما می کنیم اینه که تأمین کننده تبلیغات رو به صورت یه اینترفیس به صورت زیر تعریف می کنیم:

قدم اول: تعریف اینترفیس

  1.  
  2. public interface IAdsSuggestionProvider
  3. {
  4. ICollection<Advertisements> ProvideAds();
  5. }

قدم دوم: تغییر کلاس UserController

حالا باید کلاس UserController رو تغییر بدیم به صورتی که به جای اینکه مستقیم خودش از دیتابیس استفاده کنه، فقط یه تأمین کننده دریافت کنه و به بقیه چیزا کاری نداشته باشه.

در اصل کلاس UserController به تأمین کننده ای که داره از Constructor ش دریافت می کنه، میگه: برام مهم نیست که چی هستی و تبلیغات رو از کجا میاری فقط به من برسونش.


  1. public class UserController
  2. {
  3. private IAdsSuggestionProvider _provider;

  4. public UserController(IAdsSuggestionProvider provider)
  5. {
  6. this._provider = provider;
  7. }

  8. public void ShowAds()
  9. {
  10. foreach (var item in _provider.ProvideAds())
  11. {
  12. // نمایش تبلیغات
  13. }
  14. }
  15. }

قدم سوم: پیاده سازی کلاس هایی که یکی تبلیغات رو بر حسب برچسپ پیدا کنه و اون یکی هم که بر حسب موتور هوش مصنوعی

پس دو تا کلاس داریم که هر دو IAdsSuggestionProvider رو پیاده سازی می کنن:


  1. // این کلاس تبلیغات رو از دیتابیس بر حسب تگ پیدا می کنه
  2. public class TagAdProvider: IAdsSuggestionProvider
  3. {
  4. public ICollection<Advertisements> ProvideAds()
  5. {
  6. return GetFromDbByTag();
  7. }
  8. }
  9.  
  10. //// این یکی هم از هوش مصنوعی کمک میگیره تا تبلیغات رو پیدا کنه
  11. public class AIAdProvider: IAdsSuggestionProvider
  12. {
  13. public ICollection<Advertisements> ProvideAds()
  14. {
  15. return ArtificialIntelligence.GetAds();
  16. }
  17. }

باور کنید یا نکنید، دیگه کارمون تمومه. حالا فقط موقعی که می خوایم از کلاس UserController استفاده کنیم هر کدوم از اینا رو که خواستیم به Constructor ش ارسال می کنیم. اینطوری:


  1. // کنترلر با استفاده از تگ
  2. UserController controller = new UserController(new TagAdProvider());
  3. controller.ShowAds()

  4. // کنترلر با استفاده از هوش مصنوعی
  5. UserController controllerByAI = new UserController(new AIAdProvider());
  6. controllerByAI.ShowAds()

یعنی واقعاً وقتی خواستیم برنامه رو تغییر بدیم، اصلاً نیاز نیست کد رو زیاد تغییر بدیم و فقط باید موقعی که از کلاس UserController استفاده می کنیم اون تأمین کننده دلخواه رو به Constructor ش پاس بدیم و تمام!

بعداً این موضوع وقتی از یه مکانیزم Dependency Injection استفاده می کنیم خیلی خیلی جالب تر میشه و حتی اون موقع همین یه نیم خط تغییر تو کد رو هم بعضی وقتا لازم نیست بدیم.

نظرات (4) -

  • ali reza

    05/24/1394 11:03:03 ب.ظ | پاسخ به این نظر

    سلام
    میگیم که اینترفیس ها باعث میشن که کد های ما خلاصه بشن...
    ولی در مثال هایی که در سایت های مختلف هست میبینیم که با نوشتن اینترفیس چند خط کد بیشتر نوشته شده.مثل زیر
    using System;

    namespace ConsoleApplication5
    {
        interface ID
        {
            string fullName { get; set; }
            byte age { get; set; }
            string email { get; set; }
        }

        class ImplementInterface : ID
        {
            string _fullName;
            byte _age;
            string _email;
           public string fullName
            {
                get { return this._fullName; }
                set { this._fullName = value; }
            }

            public byte age
           {
               get { return this._age; }
               set { this._age = value; }
           }

            public string email
            {
                get { return this._email; }
                set { this._email = value; }
            }
        }
        
        class Program
        {
            static void Main(string[] args)
            {
                ImplementInterface imp = new ImplementInterface();
                Console.Write("Enter your name : ");
                string name = Console.ReadLine();
                Console.Write("Enter your age : ");
                byte age = byte.Parse( Console.ReadLine());
                Console.Write("Enter your email : ");
                string email = Console.ReadLine();
                imp.fullName = name;
                imp.age = age;
                        imp.email = email;
                        Console.Clear();
                        Console.WriteLine("Name : {0} \n\t Age : {1} \n\t\t Email : {2}", imp.fullName, imp.age, imp.email);
    }

    چون در اینصورت با ننوشتن اینترفیس هیج تغییری ایجاد نمیشه...و کد به نظر من خلاصه تره.مگر اینکه در کاربرد های دیگر باعث خلاصه شدن بشه...
    ممنون میشم اگه یک مثال کاربردی و مفصل تر بدید.....

    • حسن

      05/25/1394 08:37:55 ق.ظ | پاسخ به این نظر

      اینترفیس الزاماً باعث نمیشه که کد خلاصه تر بشه.
      در اصل باعث میشه که کد ما قابلیت به روزرسانی راحت تری داشته باشه.

      ضمن اینکه دهها کاربرد مهم دیگه هم داره Smile مثلاً قابلیت گسترش پذیری به نرم افزار میده و... .

  • ایمان

    05/25/1394 06:44:12 ب.ظ | پاسخ به این نظر

    سلام و خسته نباشید بر سید عزیز.
    سید جان خیلی خیلی ممنونم.
    واقعا از شما عزیز سپاسگزارم.

    در خصوص delegate و  attributes اگر می شود توضیح دهید خصوصا که چه کاربرد و کارایی در پروژه ها دارند. این خیلی مهمه که کاربرد و کارایی را در پروژه ها بفهمیم.

    آرزوی سلامتی از درگاه حق برای شما سید عزیز و خانواده گرامی دارم.
    افغان پیروز و زنده باشد.
    یا حق.

    • حسن

      05/25/1394 06:59:12 ب.ظ | پاسخ به این نظر

      سلام، خواهش می کنم.
      انشاءالله در اولین فرصت در اون موارد هم پست می ذارم.

Loading