JavaRush /وبلاگ جاوا /Random-FA /رابط ها در جاوا

رابط ها در جاوا

در گروه منتشر شد
سلام! امروز ما در مورد یک مفهوم مهم در جاوا صحبت خواهیم کرد - رابط ها. احتمالاً این کلمه برای شما آشناست. به عنوان مثال، اکثر برنامه ها و بازی های کامپیوتری دارای رابط هستند. در یک مفهوم گسترده، یک رابط نوعی "کنترل از راه دور" است که دو طرف را که با یکدیگر تعامل دارند، به هم متصل می کند. یک مثال ساده از یک رابط از زندگی روزمره یک کنترل از راه دور تلویزیون است. این دو شی، یک فرد و یک تلویزیون را به هم متصل می کند و وظایف مختلفی را انجام می دهد: صدا را کم یا زیاد کنید، کانال را تغییر دهید، تلویزیون را روشن یا خاموش کنید. یک طرف (فرد) باید به رابط دسترسی داشته باشد (دکمه کنترل از راه دور را فشار دهید) تا طرف دیگر این عمل را انجام دهد. به عنوان مثال، برای اینکه تلویزیون کانال را به کانال بعدی تغییر دهد. در این صورت کاربر نیازی به دانستن دستگاه تلویزیون و نحوه اجرای فرآیند تغییر کانال در داخل آن ندارد. چرا رابط ها در جاوا مورد نیاز است - 1تنها چیزی که کاربر به آن دسترسی دارد رابط است . وظیفه اصلی رسیدن به نتیجه مطلوب است. این چه ربطی به برنامه نویسی و جاوا داره؟ Direct :) ایجاد یک رابط بسیار شبیه به ایجاد یک کلاس معمولی است، اما به جای کلمه classکلمه را مشخص می کنیم interface. بیایید به ساده ترین رابط جاوا نگاه کنیم و بفهمیم که چگونه کار می کند و برای چه چیزی مورد نیاز است:
public interface Swimmable  {

     public void swim();
}
ما یک رابط ایجاد کردیم Swimmableکه می تواند شنا کند . این چیزی شبیه کنترل از راه دور ما است که یک "دکمه" دارد: روش swim() "شنا" است. چگونه می توانیم از این " کنترل از راه دور " استفاده کنیم ؟ برای این منظور روش، i.e. دکمه روی کنترل از راه دور ما باید اجرا شود. برای استفاده از یک رابط، متدهای آن باید توسط برخی از کلاس های برنامه ما پیاده سازی شود. بیایید کلاسی را پیدا کنیم که اشیاء آن با توصیف «می توانند شنا کنند» مطابقت داشته باشند. به عنوان مثال، کلاس اردک مناسب است Duck:
public class Duck implements Swimmable {

    public void swim() {
        System.out.println("Duck, swim!");
    }

    public static void main(String[] args) {

        Duck duck = new Duck();
        duck.swim();
    }
}
اینجا چه می بینیم؟ یک کلاس با استفاده از کلمه کلیدی Duckبا یک رابط مرتبط است . اگر به خاطر داشته باشید، ما از مکانیزم مشابهی برای اتصال دو کلاس در ارث استفاده کردیم، فقط کلمه " exts " وجود داشت. " " را می توان به معنای واقعی کلمه برای وضوح ترجمه کرد: "یک کلاس عمومی رابط را پیاده سازی می کند ." این بدان معنی است که یک کلاس مرتبط با یک رابط باید تمام متدهای خود را پیاده سازی کند. لطفا توجه داشته باشید: در کلاس ما، درست مانند رابط کاربری ، یک متد وجود دارد و در داخل آن نوعی منطق وجود دارد. این یک الزام اجباری است. اگر فقط “ ” را می نوشتیم و متدی را در کلاس ایجاد نمی کردیم ، کامپایلر به ما یک خطا می دهد: Duck انتزاعی نیست و متد انتزاعی swim() را در Swimable لغو نمی کند چرا این اتفاق می افتد؟ اگر خطا را با استفاده از مثال تلویزیون توضیح دهیم، معلوم می شود که از تلویزیونی که نمی داند چگونه کانال را تغییر دهد، یک کنترل از راه دور با دکمه "تغییر کانال" به شخصی می دهیم. در این مرحله، هر چقدر که دوست دارید دکمه را فشار دهید، هیچ چیز کار نمی کند. خود کنترل از راه دور کانال ها را تغییر نمی دهد: فقط سیگنالی به تلویزیون می دهد که در داخل آن یک فرآیند پیچیده تغییر کانال اجرا می شود. اردک ما هم همینطور است: باید بتواند شنا کند تا بتوان با استفاده از رابط به آن دسترسی داشت . اگر او نداند چگونه این کار را انجام دهد، رابط دو طرف - شخص و برنامه را به هم متصل نمی کند. یک شخص نمی تواند از روشی برای شناور کردن یک شی در داخل یک برنامه استفاده کند. اکنون به وضوح دیدید که رابط ها برای چه هستند. یک اینترفیس رفتاری را توصیف می کند که کلاس هایی که آن رابط را پیاده سازی می کنند باید داشته باشند. "رفتار" مجموعه ای از روش ها است. اگر می خواهیم چندین پیام رسان ایجاد کنیم، ساده ترین راه برای انجام این کار ایجاد یک رابط است . هر پیام رسان باید چه کاری انجام دهد؟ به صورت ساده، پیام ها را دریافت و ارسال کنید. Swimmableimplementspublic class Duck implements SwimmableDuckSwimmableDuckSwimmableswim()public class Duck implements Swimmableswim()DuckSwimmableSwimmableswim()DuckMessenger
public interface Messenger{

     public void sendMessage();

     public void getMessage();
}
و اکنون ما می توانیم به سادگی با پیاده سازی این رابط، کلاس های پیام رسان خود را ایجاد کنیم. خود کامپایلر ما را مجبور می کند تا آنها را در کلاس ها پیاده سازی کنیم. تلگرام:
public class Telegram implements Messenger {

    public void sendMessage() {

        System.out.println("Sending a message to Telegram!");
    }

     public void getMessage() {
         System.out.println("Reading the message in Telegram!");
     }
}
واتس اپ:
public class WhatsApp implements Messenger {

    public void sendMessage() {

        System.out.println("Sending a WhatsApp message!");
    }

     public void getMessage() {
         System.out.println("Reading a WhatsApp message!");
     }
}
وایبر:
public class Viber implements Messenger {

    public void sendMessage() {

        System.out.println("Sending a message to Viber!");
    }

     public void getMessage() {
         System.out.println("Reading a message in Viber!");
     }
}
این چه مزایایی دارد؟ مهمترین آنها کوپلینگ شل است. تصور کنید که ما در حال طراحی برنامه ای هستیم که در آن داده های مشتری را جمع آوری می کنیم. کلاس Clientباید یک فیلد داشته باشد که نشان دهد مشتری از کدام پیام رسان استفاده می کند. بدون رابط ها عجیب به نظر می رسد:
public class Client {

    private WhatsApp whatsApp;
    private Telegram telegram;
    private Viber viber;
}
ما سه فیلد ایجاد کردیم، اما یک کلاینت به راحتی می تواند تنها یک پیام رسان داشته باشد. ما فقط نمی دانیم کدام یک. و برای اینکه بدون ارتباط با مشتری باقی نمانید، باید تمام گزینه های ممکن را به کلاس "فشار دهید". معلوم می شود که یک یا دو نفر از آنها همیشه آنجا خواهند بود nullو اصلاً برای کارکرد برنامه به آنها نیازی نیست. در عوض، بهتر است از رابط کاربری خود استفاده کنید:
public class Client {

    private Messenger messenger;
}
این یک نمونه از "کوپلینگ شل" است! به جای تعیین یک کلاس پیام رسان خاص در کلاس Client، به سادگی اشاره می کنیم که کلاینت یک پیام رسان دارد. کدام یک در طول برنامه مشخص می شود. اما چرا ما به اینترفیس برای این کار نیاز داریم؟ اصلا چرا به زبان اضافه شدند؟ سوال خوب و درستی است! همین نتیجه را می توان با استفاده از وراثت معمولی به دست آورد، درست است؟ طبقه Messengerطبقه والد است، و Viber، Telegramو WhatsAppوارثان هستند. در واقع امکان انجام این کار وجود دارد. اما یک شکار وجود دارد. همانطور که می دانید، در جاوا وراثت چندگانه وجود ندارد. اما پیاده سازی های متعددی از رابط ها وجود دارد. یک کلاس می تواند هر تعداد اینترفیس را که دوست دارد پیاده سازی کند. تصور کنید که ما کلاسی داریم Smartphoneکه یک فیلد دارد Application- یک برنامه کاربردی نصب شده بر روی تلفن هوشمند.
public class Smartphone {

    private Application application;
}
برنامه و پیام رسان البته شبیه به هم هستند، اما با این وجود چیزهای متفاوتی هستند. مسنجر می تواند هم موبایل و هم دسکتاپ باشد، در حالی که Application یک اپلیکیشن موبایل است. بنابراین، اگر از وراثت استفاده کنیم، نمی‌توانیم یک شی Telegramبه کلاس اضافه کنیم Smartphone. به هر حال، یک کلاس Telegramنمی تواند از Applicationو از آن ارث ببرد Messenger! و ما قبلاً موفق شده ایم آن را از ارث ببریم Messengerو به این شکل به کلاس اضافه کنیم Client. اما یک کلاس Telegramبه راحتی می تواند هر دو اینترفیس را پیاده سازی کند! بنابراین، در یک کلاس Clientمی‌توانیم یک شی را Telegramبه‌عنوان Messengerو در کلاسی Smartphoneبه‌عنوان پیاده‌سازی کنیم Application. در اینجا نحوه انجام آن آمده است:
public class Telegram implements Application, Messenger {

    //...methods
}

public class Client {

    private Messenger messenger;

    public Client() {
        this.messenger = new Telegram();
    }
}


public class Smartphone {

    private Application application;

    public Smartphone() {
        this.application = new Telegram();
    }
}
Telegramحالا می توانیم هر طور که می خواهیم از کلاس استفاده کنیم . جایی در نقش Application, جایی در نقش Messenger. احتمالاً قبلاً متوجه شده اید که روش ها در رابط ها همیشه "خالی" هستند، یعنی پیاده سازی ندارند. دلیل این امر ساده است: یک رابط رفتار را توصیف می کند، نه آن را پیاده سازی می کند. «همه اشیاء کلاس‌هایی که اینترفیس را پیاده‌سازی می‌کنند Swimmableباید بتوانند شناور شوند»: این تمام چیزی است که رابط به ما می‌گوید. دقیقاً چگونه یک ماهی، اردک یا اسب شنا می کند، یک سوال برای کلاس ها Fish، Duckو Horseنه برای رابط است. همانطور که تغییر کانال وظیفه تلویزیون است. کنترل از راه دور به سادگی یک دکمه برای انجام این کار به شما می دهد. با این حال، Java8 یک اضافه جالب دارد - روش های پیش فرض. به عنوان مثال، رابط شما دارای 10 روش است. 9 مورد از آنها در کلاس های مختلف متفاوت پیاده سازی می شوند، اما یکی در همه یکسان است. قبلاً، قبل از انتشار Java8، روش‌های داخل رابط‌ها اصلاً پیاده‌سازی نمی‌شدند: کامپایلر فوراً یک خطا ایجاد کرد. حالا می توانید این کار را به صورت زیر انجام دهید:
public interface Swimmable {

   public default void swim() {
       System.out.println("Swim!");
   }

   public void eat();

   public void run();
}
با استفاده از کلمه کلیدی default، یک متد در رابط با یک پیاده سازی پیش فرض ایجاد کردیم. ما باید دو متد دیگر eat()و run()خودمان را در تمام کلاس هایی که پیاده سازی می کنیم پیاده سازی کنیم Swimmable. نیازی به انجام این کار با متد نیست swim(): پیاده سازی در همه کلاس ها یکسان خواهد بود. به هر حال، شما بیش از یک بار در کارهای گذشته با اینترفیس مواجه شده اید، اگرچه خودتان متوجه آن نشده اید :) در اینجا یک مثال واضح است: چرا در جاوا به رابط نیاز داریم - 2شما با رابط ها Listو Set! به طور دقیق تر، با پیاده سازی های آنها - ArrayList، LinkedList، HashSetو دیگران. همان نمودار مثالی را نشان می دهد که یک کلاس چندین رابط را همزمان پیاده سازی می کند. به عنوان مثال، LinkedListاینترفیس ها Listو Deque(صف دو طرفه) را پیاده سازی می کند. شما همچنین با رابط Mapیا بهتر است بگوییم با پیاده سازی آن آشنا هستید - HashMap. به هر حال، در این نمودار می توانید یک ویژگی را مشاهده کنید: رابط ها را می توان از یکدیگر به ارث برد. رابط SortedMapاز صف به ارث برده می شود Mapو Dequeاز صف به ارث می رسد Queue. اگر می‌خواهید ارتباط بین رابط‌ها را نشان دهید، این امر ضروری است، اما یک رابط نسخه توسعه‌یافته دیگری است. بیایید به یک مثال با یک رابط Queue- یک صف نگاه کنیم. ما هنوز مجموعه ها را مرور نکرده ایم Queue، اما آنها کاملا ساده هستند و مانند یک صف معمولی در یک فروشگاه چیده شده اند. شما می توانید عناصر را فقط به انتهای صف اضافه کنید و آنها را فقط از ابتدا حذف کنید. در یک مرحله خاص، توسعه دهندگان به یک نسخه توسعه یافته از صف نیاز داشتند تا بتوان عناصر را از هر دو طرف اضافه و دریافت کرد. به این ترتیب یک رابط ایجاد شد Deque- یک صف دو طرفه. این شامل تمام متدهای یک صف معمولی است، زیرا "والد" یک صف دو طرفه است، اما روش های جدیدی اضافه شده است.
نظرات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION