JavaRush /Java Blog /Random-ID /Antarmuka untuk mereka yang “sangat tertarik, tetapi tida...
Lilly
Level 25
Москва

Antarmuka untuk mereka yang “sangat tertarik, tetapi tidak mengerti apa pun”

Dipublikasikan di grup Random-ID
Halo semua! Posting ini ditulis untuk mereka yang telah melihat dan bahkan memecahkan beberapa masalah pada Antarmuka di level 12 (Java Core level 2), tetapi masih bertanya-tanya: “Jadi mengapa mereka diperlukan jika Anda masih perlu mengimplementasikan metode di dalamnya ?" dinyatakan di antarmuka??? Artinya, mereka tidak mengurangi jumlah kode!!!" . Saya yakin topik ini akan dibahas dalam kuliah berikutnya, dan makna yang lebih dalam serta opsi untuk menggunakan antarmuka akan terungkap, tetapi jika Anda benar-benar merasa tidak nyaman, silakan. Awalnya saya ingin menulis komentar, tetapi saya menyadari bahwa komentar itu akan sangat panjang, jadi inilah kami. Ini adalah artikel pertama saya, saya menyambut kritik yang masuk akal. Jika saya salah di suatu tempat, silakan koreksi saya. Jadi, seperti yang kita ketahui, ketika membuat kelas sendiri, kita hanya dapat mewarisi dari satu kelas abstrak atau non-abstrak . Namun pada saat yang sama, di kelas kita, kita dapat mengimplementasikan antarmuka dalam jumlah yang cukup besar . Saat mewarisi, Anda harus berpedoman pada akal sehat dan tetap menuliskan entitas terkait ke dalam keturunan Anda (kami tidak akan mewarisi kucing dari buldoser dan sebaliknya). Dengan antarmuka , logikanya sedikit berbeda: yang penting di sini bukanlah “entitas” itu sendiri, tetapi “keterampilan” mereka atau apa yang dapat dilakukan dengan mereka . Misalnya, kucing dan buldoser bisa bergerak di luar angkasa. Artinya, pada prinsipnya, mereka dapat mengimplementasikan antarmuka CanMove atau Moveable. Atau seorang pria dan seekor kucing. Mereka berdua bisa minum, tapi cara mereka melakukannya berbeda: seseorang minum teh atau kopi dari cangkir, dan kucing meminum air atau susu dari mangkuk. Namun secara umum keduanya sama-sama minum, sehingga masing-masing dapat membuat implementasi antarmuka CanDrink sendiri. Apa manfaatnya bagi kita? Bayangkan Anda sedang membuat sebuah game. Katakanlah Anda memiliki lokasi: sungai, dengan tepian di kedua sisinya, lalu hutan dan pegunungan. Berbagai jenis makhluk hidup beristirahat di tepi pantai. Tiba-tiba banjir mendekat. Setiap orang yang bisa terbang akan terbang menjauh. Mereka yang tidak bisa terbang, tapi bisa berlari, lari. Seseorang tahu cara berenang, jadi pada prinsipnya mereka tidak peduli dengan banjir Anda (atau mereka bisa berenang ke darat), meskipun beberapa dari mereka mungkin mencoba melarikan diri terlebih dahulu (jika mereka tahu caranya). Sisanya, meskipun menyedihkan, akan mati. Mari kita coba menerapkannya. (Jangan takut dengan banyaknya kode sekaligus =) Kebanyakan adalah komentar) Kelas apa yang mungkin kita perlukan? Mari kita mulai dengan kelas abstrak karakter atau unit yang berbeda (maaf, saya tidak pandai dalam terminologi permainan, koreksi jika saya salah). Biarkan ini menjadi kelas Unit . Kami berasumsi bahwa semua unit benar-benar dapat bergerak di ruang angkasa dan mengeluarkan suara. 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();
    }
}
Antarmuka (“keterampilan”) apa yang dibutuhkan unit kita? Mereka dapat berlari ( CanRun ), berenang ( CanSwim ) atau terbang ( CanFly ). Beberapa orang mungkin memiliki beberapa keterampilan sekaligus, sementara beberapa orang yang kurang beruntung mungkin tidak memilikinya.

// Интерфейсы. КАЖДЫЙ КЛАСС, "наследующий" Howой-то интерфейс,
// ДОЛЖЕН РЕАЛИЗОВАТЬ его у себя.
interface CanRun {
    void run(String action);
}
interface CanSwim {
    void swim();
}
interface CanFly {
    void fly();
}
Selanjutnya kita membuat kelas yang mewarisi dari kelas Unit abstrak. Jalurnya 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 mengerti bahwa tidak ada burung yang sederhana, tetapi demi kesederhanaan, biarlah hanya seekor burung, jangan dibuat 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 buat kelas abstrak lainnya Animals , yang akan diwarisi dari Unit :

// Абстрактный класс Животных, НАСЛЕДУЕТ абстрактный класс Unit
public static abstract class Animal extends Unit {
    // тут могут быть Howие-то данные и/or методы
}
Dan sudah menjadi ahli warisnya 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 ( Kemalasan ):

// Ленивец НАСЛЕДУЕТ класс 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) + " вперед");
    }
}
Metode move(int x, int y) dari kelas Unit abstrak bukanlah abstract , jadi kita tidak perlu menimpanya, tapi kita sedikit memperlambatnya untuk Sloth. Sekarang mari kita beralih ke 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() + " ) умер");
}
Literal numerik 12, 50, 400 dan 1000 diambil begitu saja; yang lain dapat ditentukan, tapi saya harap logikanya jelas. Jadi, seperti yang bisa kita lihat, dengan memiliki kelas induk abstrak dengan metode umum, kita tidak perlu memikirkan kelas spesifik unit ini atau itu, tetapi cukup panggil metode ini ( makeSound() dan move ( ) ) . Setelah pass pertama dalam loop, ketika metode move() dipanggil pada semua unit , berikut ini akan ditampilkan pada layar: Antarmuka untuk mereka yang “sangat tertarik, tetapi tidak mengerti apa pun” - 1 Tentu saja, semua objek kecuali sloth menampilkan pesan standar dari metode move() dari induk abstrak kelas Unit , dan kemalasan memiliki gerakan (metode) yang telah didefinisikan ulang . Namun, kelas abstrak tidak akan membantu kita mengetahui apa yang “dapat dilakukan” oleh unit tertentu. Di sinilah antarmuka berperan . Dengan menggunakan instanceof , kita mengetahui apakah unit ini dapat melakukan tindakan tertentu ( apakah mendukung antarmuka yang kita butuhkan ), dan jika demikian, kita menggunakan tipe casting yang sudah kita kenal, misalnya menggunakan ((CanFly) unit). fly() kita melemparkan objek tipe Unit ke tipe antarmuka CanFly dan memanggil metode fly() -nya . Dan tidak peduli kelas apa yang dimiliki objek kita, satu-satunya hal yang penting adalah ia menunjukkan kemampuan terbang di "resume" -nya. Kami memberitahunya: "Kamu tahu caranya, jadi terbanglah! Kami tidak peduli bagaimana kamu melakukannya . " Artinya, bagi kami sebagai pengembang, ini berarti bahwa kelas yang mengimplementasikan antarmuka CanFly dapat mengubah implementasi metode fly() kapan saja dan dengan cara apa pun , kelas baru yang mengimplementasikannya dapat muncul, atau sebaliknya, pengembang dapat hapus beberapa kelas lama. Namun selama metode ini menjalankan fungsinya dan objeknya terbang, kami tidak peduli. Kode kita yang bekerja dengan objek yang mengimplementasikan antarmuka ini akan tetap sama; kita tidak perlu mengubah apa pun. Setelah siklus kedua, ketika semua orang mencoba melarikan diri, tergantung pada skala banjir, kita akan melihat di layar atau Antarmuka untuk mereka yang “sangat tertarik, tetapi tidak mengerti apa pun” - 2 Tanpa Antarmuka untuk mereka yang “sangat tertarik, tetapi tidak mengerti apa pun” - 3 antarmuka, kita harus memeriksa kepatuhan setiap objek dengan kelas tertentu (dan kita akan melakukannya untuk memeriksa semuanya) dan mengingat keterampilan masing-masing kelas tertentu. Artinya, ada seekor domba di depan kita sekarang dan sepertinya dia tahu cara berlari. Bagaimana jika Anda memiliki beberapa lusin atau ratusan tipe (kelas) karakter yang berbeda? Dan bagaimana jika bukan Anda yang menulisnya, tapi programmer lain, jadi Anda tidak tahu siapa yang bisa melakukan apa? Itu akan jauh lebih sulit... Dan tambahan kecil setelah publikasi: Dalam kehidupan nyata, Anda bukan satu-satunya yang mengerjakan sebuah proyek. Katakanlah Anda hanya melakukan logika. Semua objek yang berinteraksi dengan Anda ditulis oleh pemrogram lain. Anda bahkan mungkin tidak mengetahui semua kelas tempat kode Anda bekerja. Yang Anda butuhkan dari mereka adalah mereka melakukan apa yang Anda ingin mereka lakukan. Namun, mereka semua dapat melakukannya dengan cara yang sangat berbeda. Namun, katakanlah, dalam kode Anda, Anda membuat metode yang hanya berfungsi dengan objek kelas yang mendukung antarmuka tertentu

void doSomething(CanFly f)
yaitu, Anda mengatur antarmuka menggunakan parameter metode. Bukan kelas konkrit, tapi antarmuka. Dan semua pemrogram lainnya, ketika memanggil metode void doSomething(CanFly) milik Anda, harus memberikan argumen baik secara eksplisit objek dari kelas yang mengimplementasikan CanFly, atau beberapa objek dari beberapa kelas yang dapat dimasukkan ke dalamnya:

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 kegunaan antarmuka. Dan ini tidak semua kemampuan dan metode penerapannya. Kita mungkin akan mempelajarinya lebih lanjut nanti dalam kursus ini =) Terima kasih telah membaca sampai akhir =)
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION