JavaRush /Java Blog /Random-TL /Mga interface para sa mga "napakainteresado, ngunit walan...
Lilly
Antas
Москва

Mga interface para sa mga "napakainteresado, ngunit walang naiintindihan"

Nai-publish sa grupo
Kamusta kayong lahat! Ang post na ito ay isinulat, sa halip, para sa mga nakakita na at kahit na nalutas ang ilang mga problema sa Mga Interface sa antas 12 (2nd antas ng Java Core), ngunit nagtataka pa rin: "Kaya bakit kailangan ang mga ito kung kailangan mo pa ring ipatupad ang mga pamamaraan sa kanila ?” ipinahayag sa interface??? Ibig sabihin, hindi nila binabawasan ang dami ng code!!!" . Wala akong pag-aalinlangan na ang paksang ito ay tatalakayin sa mga susunod na lektura, at mas malalalim na kahulugan at mga opsyon para sa paggamit ng mga interface ang ihahayag, ngunit kung ikaw ay ganap na hindi mapalagay, ikaw ay malugod na tinatanggap. Noong una gusto kong magsulat ng komento, ngunit napagtanto ko na ito ay magiging isang napakahabang komento, kaya narito kami. Ito ang aking unang artikulo, tinatanggap ko ang makatwirang pagpuna. Kung ako ay mali sa isang lugar, huwag mag-atubiling itama ako. Kaya, tulad ng alam natin, kapag lumilikha ng sarili nating klase, maaari lang tayong magmana mula sa isang abstract o hindi abstract na klase . Ngunit sa parehong oras, sa aming klase maaari naming ipatupad ang isang medyo malaking bilang ng mga interface . Kapag nagmana, kailangan mong gabayan ng sentido komun at isulat pa rin ang mga nauugnay na entity sa iyong mga inapo (hindi kami magmamana ng pusa mula sa isang bulldozer at vice versa). Sa mga interface , medyo naiiba ang lohika: ang mahalaga dito ay hindi ang "mga entidad" mismo, ngunit ang kanilang "kasanayan" o kung ano ang maaaring gawin sa kanila . Halimbawa, ang isang pusa at isang bulldozer ay maaaring lumipat sa kalawakan. Iyon ay, sa prinsipyo, maaari nilang ipatupad ang CanMove o Moveable na interface. O isang lalaki at isang pusa. Pareho silang maaaring uminom, ngunit ginagawa nila ito sa iba't ibang paraan: ang isang tao ay umiinom ng tsaa o kape mula sa isang tasa, at ang isang pusa ay umiinom ng tubig o gatas mula sa isang mangkok. Ngunit sa pangkalahatan, pareho silang umiinom, kaya bawat isa sa kanila ay maaaring gumawa ng kanilang sariling pagpapatupad ng interface ng CanDrink. Ano ang pakinabang nito para sa atin? Isipin na gumagawa ka ng isang laro. Sabihin nating mayroon kang lokasyon: isang ilog, na may mga pampang sa magkabilang gilid nito, at pagkatapos ay isang kagubatan at mga bundok. Iba't ibang uri ng buhay na nilalang ang namamalagi sa dalampasigan. Biglang lumalapit ang baha. Lahat ng makakalipad ay lilipad. Ang mga hindi lumipad, ngunit maaaring tumakbo, tumakbo. May isang taong marunong lumangoy, kaya sa prinsipyo wala silang pakialam sa iyong baha (mabuti, o kaya nilang lumangoy sa pampang), bagaman ang ilan sa kanila ay maaaring subukan munang tumakas (kung alam nila kung paano). Ang iba, malungkot man, ay mamamatay. Subukan nating ipatupad ito. (Huwag matakot sa malaking halaga ng code nang sabay-sabay =) Karamihan dito ay mga komento) Anong mga klase ang maaaring kailanganin natin? Magsimula tayo sa isang abstract na klase ng iba't ibang mga character o unit (paumanhin, hindi ako malakas sa terminolohiya sa paglalaro, itama ako kung mali ako). Hayaang ito ang klase ng Unit . Ipagpalagay namin na ganap na lahat ng mga yunit ay maaaring lumipat sa kalawakan at gumawa ng mga tunog. Abstract na Yunit ng klase :
// Абстрактный класс для всех юнитов
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();
    }
}
Anong mga interface ("kasanayan") ang kailangan ng ating mga unit? Maaari silang tumakbo ( CanRun ), lumangoy ( CanSwim ) o lumipad ( CanFly ). Ang ilang mga tao ay maaaring magkaroon ng ilang mga kasanayan nang sabay-sabay, habang ang ilang mga kapus-palad na mga tao ay maaaring wala.
// Интерфейсы. КАЖДЫЙ КЛАСС, "наследующий" Howой-то интерфейс,
// ДОЛЖЕН РЕАЛИЗОВАТЬ его у себя.
interface CanRun {
    void run(String action);
}
interface CanSwim {
    void swim();
}
interface CanFly {
    void fly();
}
Susunod na lumikha kami ng mga klase na nagmana mula sa abstract na klase ng Unit. Ang landas ay magiging klase ng Tao :
// Человек НАСЛЕДУЕТ абстрактный класс 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() + " ) " +
                           "с двумя руками и двумя ногами " +
                           "хорошо плаваю");
    }
}
Klase ng ibon . Oo, naiintindihan ko na walang mga simpleng ibon, ngunit para sa kapakanan ng pagiging simple, hayaan itong maging isang ibon lamang, huwag nating gawing abstract:
// Птица НАСЛЕДУЕТ абстрактный класс 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() + " ) улетел отсюда");
    }
}
Ngayon gumawa tayo ng isa pang abstract class na Animals , na mamanahin mula sa Unit :
// Абстрактный класс Животных, НАСЛЕДУЕТ абстрактный класс Unit
public static abstract class Animal extends Unit {
    // тут могут быть Howие-то данные и/or методы
}
At ang kanyang mga tagapagmana na Kordero ( Tupa ):
// Баран НАСЛЕДУЕТ класс 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 +
                           " отсюда на четырёх копытах");
    }
}
at Sloth ( 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) + " вперед");
    }
}
Ang move(int x, int y) na paraan ng abstract Unit class ay hindi abstract , kaya hindi namin kailangang i-override ito, ngunit medyo pinabagal namin ang mga bagay para sa Sloth. Ngayon ay lumipat tayo sa pagkilos.
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() + " ) умер");
}
Ang mga numeric na literal na 12, 50, 400 at 1000 ay kinuha kaagad; ang iba ay maaaring tukuyin, ngunit inaasahan kong malinaw ang lohika. Kaya, tulad ng nakikita natin, ang pagkakaroon ng abstract na klase ng magulang na may mga pangkalahatang pamamaraan, hindi natin kailangang isipin kung anong partikular na klase ito o ang yunit na iyon, ngunit tawagan lamang ang mga pamamaraang ito ( makeSound() at move ( ) ) . Pagkatapos ng unang pass sa loop, kapag ang move() method ay tinawag sa lahat ng unit , ang mga sumusunod ay ipapakita sa screen: Mga interface para sa mga "napakainteresado, ngunit walang naiintindihan" - 1 Malinaw, lahat ng object maliban sa sloth ay nagpapakita ng karaniwang mensahe mula sa move() method ng abstract na magulang class Unit , at ang sloth ay may move( method ) ay na- redefined . Gayunpaman, ang isang abstract na klase ay hindi makakatulong sa amin na malaman kung ano ang "magagawa" ng isang partikular na yunit. Dito pumapasok ang mga interface . Gamit ang instanceof , malalaman namin kung makakagawa ang unit na ito ng ilang partikular na pagkilos ( kung sinusuportahan nito ang interface na kailangan namin ), at kung gayon, ginagamit namin ang uri ng casting na pamilyar na sa amin, halimbawa, gamit ang ((CanFly) unit). fly() inihagis namin ang aming Unit type object sa CanFly interface type at tinatawag ang fly() method nito . At hindi mahalaga kung anong klase ang mayroon ang ating bagay, ang mahalaga lang ay ipinahiwatig niya ang kakayahang lumipad sa kanyang "resume". Sinabi namin sa kanya: "Alam mo kung paano, kaya lumipad ka! Wala kaming pakialam kung paano mo ito gagawin . " Ibig sabihin, para sa amin, bilang mga developer, nangangahulugan ito na ang mga klase na nagpapatupad ng interface ng CanFly ay maaaring baguhin ang pagpapatupad ng fly() na paraan sa anumang oras at sa anumang paraan , ang mga bagong klase na nagpapatupad nito ay maaaring lumitaw, o, sa kabaligtaran, ang mga developer ay maaaring alisin ang ilan sa mga lumang klase. Ngunit hangga't ginagawa ng pamamaraang ito ang mga nakasaad na function nito at lumilipad ang bagay, wala kaming pakialam. Ang aming code na gumagana sa mga bagay na nagpapatupad ng interface na ito ay mananatiling pareho; hindi namin kailangang baguhin ang anuman. Pagkatapos ng ikalawang cycle, kapag sinusubukan ng lahat na tumakas, depende sa laki ng baha, makikita natin sa screen alinman Mga interface para sa mga "napakainteresado, ngunit walang naiintindihan" - 2 o Mga interface para sa mga "napakainteresado, ngunit walang naiintindihan" - 3 Kung walang interface, kailangan nating suriin ang bawat bagay para sa pagsunod sa isang partikular na klase (at magkakaroon tayo ng upang suriin ang lahat) at isaisip ang mga kasanayan ng bawat partikular na klase . Ibig sabihin, may tupa sa harapan namin ngayon at parang marunong na itong tumakbo. Paano kung mayroon kang ilang dosena o daan-daang iba't ibang uri (klase) ng mga naturang karakter? At paano kung hindi ikaw ang sumulat sa kanila, ngunit isa pang programmer, kaya wala kang ideya kung sino ang maaaring gumawa ng ano? Ito ay magiging mas mahirap... At isang maliit na karagdagan pagkatapos ng publikasyon: Sa totoong buhay, hindi lang ikaw ang gumagawa ng project. Sabihin nating lohika lang ang ginagawa mo. Ang lahat ng mga bagay na iyong nakikipag-ugnayan ay isinulat ng ibang mga programmer. Maaaring hindi mo alam ang lahat ng mga klase na gumagana sa iyong code. Ang kailangan mo lang sa kanila ay gawin nila ang kailangan mong gawin nila. Gayunpaman, magagawa nilang lahat ito sa ganap na magkakaibang paraan. Ngunit, sabihin nating, sa iyong code ay lumikha ka ng isang paraan na gumagana lamang sa mga bagay ng mga klase na sumusuporta sa isang partikular na interface
void doSomething(CanFly f)
ibig sabihin, itinakda mo ang interface gamit ang parameter ng pamamaraan. Hindi isang kongkretong klase, ngunit isang interface. At lahat ng iba pang programmer, kapag tinatawag itong void na doSomething(CanFly) na pamamaraan mo, ay dapat pumasa bilang mga argumento alinman sa isang tahasang object ng isang klase na nagpapatupad ng CanFly, o ilang object ng ilang klase na maaaring i-cast dito:
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
Ito ay kung paano maaaring maging kapaki-pakinabang ang mga interface. At ito ay hindi lahat ng kanilang mga kakayahan at pamamaraan ng aplikasyon. Malamang marami pa tayong matutunan mamaya sa kurso =) Salamat sa pagbabasa hanggang dulo =)
Mga komento
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION