JavaRush /Blog Java /Random-MS /Antara muka untuk mereka yang "sangat berminat, tetapi ti...
Lilly
Tahap
Москва

Antara muka untuk mereka yang "sangat berminat, tetapi tidak memahami apa-apa"

Diterbitkan dalam kumpulan
Hai semua! Siaran ini ditulis, sebaliknya, untuk mereka yang telah melihat dan bahkan menyelesaikan beberapa masalah pada Antaramuka pada tahap 12 (tahap ke-2 Java Core), tetapi masih tertanya-tanya: "Jadi mengapa mereka diperlukan jika anda masih perlu melaksanakan kaedah di dalamnya ?” diisytiharkan dalam antara muka??? Iaitu, mereka tidak mengurangkan jumlah kod!!!" . Saya tidak ragu-ragu bahawa topik ini akan dibincangkan dalam kuliah berikutnya, dan makna dan pilihan yang lebih mendalam untuk menggunakan antara muka akan didedahkan, tetapi jika anda benar-benar tidak selesa, maka anda dialu-alukan. Pada mulanya saya ingin menulis komen, tetapi saya menyedari bahawa ia akan menjadi komen yang sangat panjang, jadi di sini kita berada. Ini adalah artikel pertama saya, saya mengalu-alukan kritikan yang munasabah. Jika saya salah di suatu tempat, sila betulkan saya. Jadi, seperti yang kita tahu, apabila mencipta kelas kita sendiri, kita boleh mewarisi hanya daripada satu kelas abstrak atau bukan abstrak . Tetapi pada masa yang sama, dalam kelas kami, kami boleh melaksanakan bilangan antara muka yang agak besar . Apabila mewarisi, anda perlu dibimbing oleh akal dan tetap mencatatkan entiti berkaitan ke dalam keturunan anda (kami tidak akan mewarisi kucing daripada jentolak dan sebaliknya). Dengan antara muka , logiknya sedikit berbeza: yang penting di sini bukanlah "entiti" itu sendiri, tetapi "kemahiran" mereka atau apa yang boleh dilakukan dengan mereka . Sebagai contoh, kedua-dua kucing dan jentolak boleh bergerak di angkasa. Iaitu, pada dasarnya, mereka boleh melaksanakan antara muka CanMove atau Moveable. Atau lelaki dan kucing. Mereka berdua boleh minum, tetapi mereka melakukannya dengan cara yang berbeza: seseorang minum teh atau kopi dari cawan, dan seekor kucing mengambil sedikit air atau susu dari mangkuk. Tetapi secara umum, mereka berdua minum, jadi setiap daripada mereka boleh membuat pelaksanaan sendiri antara muka CanDrink. Apakah faedahnya untuk kita? Bayangkan anda sedang membuat permainan. Katakan anda mempunyai lokasi: sungai, dengan tebing di kedua-dua belahnya, dan kemudian hutan dan gunung. Pelbagai jenis makhluk hidup berehat di pantai. Tiba-tiba banjir menghampiri. Semua orang yang boleh terbang terbang pergi. Mereka yang tidak boleh terbang, tetapi boleh berlari, berlari. Seseorang tahu bagaimana untuk berenang, jadi pada dasarnya mereka tidak mengambil berat tentang banjir anda (baik, atau mereka boleh berenang ke darat), walaupun sesetengah daripada mereka mungkin mula-mula cuba melarikan diri (jika mereka tahu caranya). Selebihnya, walaupun sedih, akan mati. Mari cuba laksanakan ini. (Jangan takut dengan jumlah kod yang banyak sekali gus =) Kebanyakannya adalah ulasan) Apakah kelas yang mungkin kita perlukan? Mari kita mulakan dengan kelas abstrak watak atau unit yang berbeza (maaf, saya tidak mahir dalam istilah permainan, betulkan saya jika saya salah). Biarkan ini menjadi kelas Unit . Kami akan menganggap bahawa semua unit boleh bergerak di angkasa dan mengeluarkan bunyi. Unit kelas abstrak :
// Абстрактный класс для всех юнитов
public static abstract class Unit {
    // Базовый метод движения.
    // По умолчанию (если не переопределено) будет у всех наследников.
    public void move (int x, int y) {
        System.out.println("Я ( " + getClassName() + " ) просто брожу по полю на " +
                           x + " метров вправо и " + y + " метров вперед");
    }

    // Абстрактный метод, который ДОЛЖЕН ПЕРЕОПРЕДЕЛИТЬ у себя
    // КАЖДЫЙ КЛАСС, унаследованный от Unit.
    public abstract void makeSound();

    // Вспомогательный метод получения имени класса
    // без всей лишней информации.
    public String getClassName() {
        return this.getClass().getSimpleName();
    }
}
Apakah antara muka (“kemahiran”) yang diperlukan oleh unit kami? Mereka boleh berlari ( CanRun ), berenang ( CanSwim ) atau terbang ( CanFly ). Sesetengah orang mungkin mempunyai beberapa kemahiran sekaligus, manakala sesetengah orang yang malang mungkin tidak mempunyainya.
// Интерфейсы. КАЖДЫЙ КЛАСС, "наследующий" Howой-то интерфейс,
// ДОЛЖЕН РЕАЛИЗОВАТЬ его у себя.
interface CanRun {
    void run(String action);
}
interface CanSwim {
    void swim();
}
interface CanFly {
    void fly();
}
Seterusnya kita mencipta kelas yang mewarisi daripada kelas Unit abstrak. Laluan akan menjadi kelas Manusia :
// Человек НАСЛЕДУЕТ абстрактный класс Unit,
// а также РЕАЛИЗУЕТ интерфейсы CanRun, CanSwim
public static class Human extends Unit implements CanRun, CanSwim {
    // Переопределяем метод public void makeSound()
    // родительского абстрактного класса Unit
    @Override
    public void makeSound() {
        System.out.print("Йу-хуу! ");
    }

    // РЕАЛИЗУЕМ метод public void run(String action) интерфейса CanRun
    @Override
    public void run(String action) {
        System.out.println("Я ( " + this.getClassName() + " ) " + action +
                           " отсюда на двух ногах ");
    }

    // РЕАЛИЗУЕМ метод public void swim() интерфейса CanSwim
    @Override
    public void swim() {
        System.out.println("Я ( " + this.getClassName() + " ) " +
                           "с двумя руками и двумя ногами " +
                           "хорошо плаваю");
    }
}
Kelas burung . Ya, saya faham bahawa tidak ada burung yang mudah, tetapi demi kesederhanaan, biarkan ia hanya seekor burung, jangan menjadikannya abstrak:
// Птица НАСЛЕДУЕТ абстрактный класс Unit,
// и РЕАЛИЗУЕТ интерфейс CanFly
public static class Bird extends Unit implements CanFly {
    // Переопределяем абстрактный метод public void makeSound()
    // родительского абстрактного класса Unit
    @Override
    public void makeSound() {
        System.out.print("Курлык! ");
    }

    // РЕАЛИЗУЕМ метод public void fly() интерфейса CanFly
    @Override
    public void fly() {
        System.out.println("Я ( " + this.getClassName() + " ) улетел отсюда");
    }
}
Sekarang mari kita cipta satu lagi kelas abstrak Animals , yang akan diwarisi daripada Unit :
// Абстрактный класс Животных, НАСЛЕДУЕТ абстрактный класс Unit
public static abstract class Animal extends Unit {
    // тут могут быть Howие-то данные и/or методы
}
Dan sudah menjadi pewarisnya Anak Domba ( Domba ):
// Баран НАСЛЕДУЕТ класс Animal,
// и РЕАЛИЗУЕТ интерфейс CanRun
public static class Sheep extends Animal implements CanRun {
    // Переопределяем абстрактный метод public void makeSound()
    // родительского абстрактного класса Unit
    @Override
    public void makeSound() {
        System.out.print("Беееее! ");
    }

    // РЕАЛИЗУЕМ метод public void run(String action) интерфейса CanRun
    @Override
    public void run(String action) {
        System.out.println("Я ( "+ this.getClassName() + " ) " + action +
                           " отсюда на четырёх копытах");
    }
}
dan Kemalasan ( Sloth ):
// Ленивец НАСЛЕДУЕТ класс Animal
// и внутри себя ПЕРЕОПРЕДЕЛЯЕТ метод
// void move(int x, int y) абстрактного класса Unit
public static class Sloth extends Animal {
    // Переопределяем абстрактный метод public void makeSound()
    // родительского абстрактного класса Unit
    @Override
    public void makeSound() {
        System.out.print("Зевает... ");
    }

	// Переопределяем метод public void move(int x, int y)
    // родительского абстрактного класса Unit
    @Override
    public void move(int x, int y) {
        System.out.println("Я ( "+ getClassName() + " ) очень медленный, поэтому " +
                           "переместился на " + (int)(x/12) + " вправо " +
                           "и на " + (int)(y/12) + " вперед");
    }
}
Kaedah move(int x, int y) kelas Unit abstrak bukan abstract , jadi kami tidak perlu mengatasinya, tetapi kami memperlahankan sedikit perkara untuk Sloth. Sekarang mari kita beralih kepada tindakan.
public static void main(String[] args) {
    // создаём список юнитов
    // и добавляем туда представителей разных классов
    List<Unit> units = new ArrayList<unit>();
    units.add(new Human());
    units.add(new Bird());
    units.add(new Sheep());
    units.add(new Sloth());

    // проходим в цикле по всем юнитам и вызываем метод move(int x, int y).
    // У всех, кроме ленивца, будет вызван метод базового класса.
    // У Ленивца будет вызван его переопределенный метод
    for (Unit unit : units) {
		// в самом начале ничего не происходит, юниты просто двигаются.
        unit.move((int)(Math.random()*50), (int)(Math.random()*50));
    }

    System.out.println("\n...Наводнение приближается....");
    int distanceOfFlood = (int)(Math.random()*1000); // Число от 0 до 1000
    System.out.println("...Наводнение на " + distanceOfFlood + " от берега...\n");

    // проходим в цикле по всем юнитам
    for (Unit unit : units) {
        unit.makeSound(); // у каждого юнита свой, переопределенный, звук
        // смотрим, кто что "умеет":
		// если юнит умеет летать
        if(unit instanceof CanFly)
            ((CanFly) unit).fly(); // проблем нет, улетает
        // если юнит не умеет летать, но умеет бегать
        else if(unit instanceof CanRun) {
			// смотрим на Howое расстояние разлилась вода
            if(distanceOfFlood < 400) {
				// если меньше 400 (условно метров)
                ((CanRun) unit).run("убежал"); // юнит убежал
            }
            else {
				// если больше 400, юнит безуспешно пытается убежать
                ((CanRun) unit).run("пытался убежать");
				// если юнит может не только бегать, но и плавать
                if (unit instanceof CanSwim) {
                    ((CanSwim) unit).swim(); // плывёт
                }
				// иначе умирает (он хотя бы пытался)
                else unitIsDead(unit);
            }
        }
		// если юнит не летает, не бегает, но может плавать
        else if (unit instanceof CanSwim)
            ((CanSwim) unit).swim(); // плывёт
        else
			// если юнит не умеет совсем ничего - грустненько :(
            unitIsDead(unit); // умирает

        System.out.println();
    }
}

public static void unitIsDead(Unit unit) {
    System.out.println("Извините, я ( " + unit.getClassName() + " ) умер");
}
Huruf angka 12, 50, 400 dan 1000 diambil begitu sahaja; yang lain boleh ditentukan, tetapi saya harap logiknya jelas. Jadi, seperti yang dapat kita lihat, mempunyai kelas induk abstrak dengan kaedah umum, kita tidak perlu memikirkan kelas khusus ini atau unit itu, tetapi cukup panggil kaedah ini ( makeSound() dan move ( ) ) . Selepas pas pertama dalam gelung, apabila kaedah move() dipanggil pada semua unit , perkara berikut akan dipaparkan pada skrin: Antara muka untuk mereka yang "sangat berminat, tetapi tidak memahami apa-apa" - 1 Jelas sekali, semua objek kecuali sloth memaparkan mesej standard daripada kaedah move() induk abstrak class Unit , dan sloth mempunyai move( method ) telah ditakrifkan semula . Walau bagaimanapun, kelas abstrak tidak akan membantu kami mengetahui perkara yang "boleh lakukan" oleh unit tertentu. Di sinilah antara muka memainkan peranan . Menggunakan instanceof , kami mengetahui sama ada unit ini boleh melakukan tindakan tertentu ( sama ada ia menyokong antara muka yang kami perlukan ), dan jika ya, kami menggunakan jenis casting yang sudah biasa kepada kami, contohnya, menggunakan unit ((CanFly). fly() kami menghantar objek jenis Unit kami ke jenis antara muka CanFly dan memanggil kaedah fly() nya . Dan tidak kira apa kelas objek kita, satu-satunya perkara penting ialah dia menunjukkan keupayaan untuk terbang dalam "resume"nya. Kami memberitahunya: "Anda tahu bagaimana, jadi terbanglah! Kami tidak peduli bagaimana anda melakukannya . " Iaitu, bagi kami, sebagai pembangun, ini bermakna kelas yang melaksanakan antara muka CanFly boleh menukar pelaksanaan kaedah fly() pada bila-bila masa dan dalam apa jua cara , kelas baharu yang melaksanakannya boleh muncul, atau, sebaliknya, pembangun boleh alih keluar beberapa kelas yang lama. Tetapi selagi kaedah ini melaksanakan fungsi yang dinyatakan dan objek itu terbang, kami tidak peduli. Kod kami yang berfungsi dengan objek yang melaksanakan antara muka ini akan kekal sama; kami tidak perlu mengubah apa-apa. Selepas kitaran kedua, apabila semua orang cuba melarikan diri, bergantung pada skala banjir, kita akan melihat pada skrin sama ada Antara muka untuk mereka yang "sangat berminat, tetapi tidak memahami apa-apa" - 2 atau Antara muka untuk mereka yang "sangat berminat, tetapi tidak memahami apa-apa" - 3 Tanpa antara muka, kita perlu menyemak setiap objek untuk pematuhan dengan kelas tertentu (dan kita akan mempunyai untuk menyemak segala-galanya) dan ingat kemahiran setiap kelas tertentu . Iaitu, ada seekor kambing di hadapan kita sekarang dan ia seolah-olah tahu bagaimana untuk berlari. Bagaimana jika anda mempunyai beberapa dozen atau beratus-ratus jenis (kelas) watak sedemikian? Dan bagaimana jika bukan anda yang menulisnya, tetapi pengaturcara lain, jadi anda tidak tahu siapa yang boleh melakukan apa? Ia akan menjadi lebih sukar... Dan tambahan kecil selepas penerbitan: Dalam kehidupan sebenar, anda bukan seorang sahaja yang bekerja pada projek. Katakan anda hanya melakukan logik. Semua objek yang anda berinteraksi ditulis oleh pengaturcara lain. Anda mungkin tidak tahu semua kelas yang berfungsi dengan kod anda. Apa yang anda perlukan daripada mereka ialah mereka melakukan apa yang anda perlukan. Walau bagaimanapun, mereka semua boleh melakukan ini dengan cara yang berbeza. Tetapi, katakan, dalam kod anda, anda mencipta kaedah yang berfungsi hanya dengan objek kelas yang menyokong antara muka tertentu
void doSomething(CanFly f)
iaitu, anda menetapkan antara muka menggunakan parameter kaedah. Bukan kelas konkrit, tetapi antara muka. Dan semua pengaturcara lain, apabila memanggil kaedah void doSomething(CanFly) anda ini, mesti lulus sebagai hujah sama ada objek secara eksplisit kelas yang melaksanakan CanFly, atau beberapa objek dari beberapa kelas yang boleh dihantar kepadanya:
Object obj = new Bird();
doSomething(obj); // ошибка компиляции Object cannot be converted to CanFly
doSomething((CanFly) obj); // нет ошибки, потому что obj у нас класса Bird и реализует CanFly

Bird b = new Bird();
doSomething(b); // нет ошибки

Human h = new Human() ;
doSomething(h); // ошибка компиляции
doSomething((CanFly) h); // ошибка времени выполнения ClassCastException
Inilah cara antara muka boleh berguna. Dan ini bukan semua keupayaan dan kaedah permohonan mereka. Kami mungkin akan mengetahui lebih lanjut dalam kursus nanti =) Terima kasih kerana membaca hingga habis =)
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION