Java týden Java týden
Pouze tento týden sleva až 80 % na celý Java e-learning!
Brno? Vypsali jsme pro vás nové termíny školení OOP v Brně!
Avatar
jip123
Člen
Avatar
jip123:24. dubna 14:33

Přátelé,
s Javou začínám a ještě se v ní moc nevyznám, už jsem k ní přečetl poměrně dost materiálů, ale co nechápu je rozhraní.
Mohl by mi někdo vysvětlit k čemu se vlastně používá, moc to nechápu a nikde jsem na to nenašel odpověď.
Četl jsem vysvětlení jako: že je to podobné jako abstraktní třída, jen že rozhraní můžeme implementovat více do dané třídy. To ještě chápu:)
A pak, že v rozhraní jsou hlavičky metod, které musím ve třídě doprogramovat. To je taky jasné, *jenže k čemu to rozhraní vlastně tedy implementovat, když ty metody si můžu doprogramovat v té třídě úplně stejně, jako když žádné rozhraní nemám...
*
Díky za vysvětlení.

Zkusil jsem: Dost jsem googlil, ale nějaké "polopatické" vysvětlení jsem nenašel. Prostudoval jsem kurz Javy i zde, ale ...

Chci docílit: Chci pochopit rozhraní v Javě.

 
Odpovědět 24. dubna 14:33
Avatar
Petr Štechmüller
Překladatel
Avatar
Odpovídá na jip123
Petr Štechmüller:24. dubna 14:56

Ahoj, rozhraní přesně jak říkáš pouze předepisuje, jaké metody musíš implementovat.

Vtip je v tom, že někdy potřebuješ dvě různé implementace jedné a té samé funkcionality. Pak vytvoříš dvě třídy, které budou implementovat jedno rozhraní, ale s rozdílnou implementací.

Nahoru Odpovědět 24. dubna 14:56
Pokud spolu kód a komentář nekorespondují, budou patrně oba chybné
Avatar
Lubor Pešek
Člen
Avatar
Odpovídá na jip123
Lubor Pešek:24. dubna 16:27

Pominu to, jak s rozhraním pracují frameworky (ty ho využívají v rámci své logiky).
Takže úplně jasný příklad v praxi.

Dávám ti zadání:
Máš třídy:

  • Main
  • Dog
  • Bird
  • Cat

Začnu třídami Dog, Bird a Cat (všechny budou velmi podobné)
Všechny tyto třídy budou mít jednu metodu - String voice()
Tato metoda bude vracet zvuk toho zvířete.

No a metoda Main bude:

  • main metoda (překvapivě:) )
  • metoda outputu, které předáš dané zvíře a ona vypíše jeho zvuk na standardní výstup.

Takže pojďme na ty první tři třídy, ty budou vypadat následovně:

public class Dog {

    public String voice() {
        return "Hafiky haf";
    }
}

public class Cat {

    public String voice() {
        return "mňau vole au";
    }
}

public class Bird {

    public String voice() {
        return "kuku";
    }
}
Nahoru Odpovědět  +4 24. dubna 16:27
Existují dva způsoby, jak vyřešit problém. Za prvé vyhoďte počítač z okna. Za druhé vyhoďte okna z počítače.
Avatar
Lubor Pešek
Člen
Avatar
Lubor Pešek:24. dubna 16:36

pardon, su vůl a dal jsem místo náhledu odeslat...

Tak a třída main bude (bez použití rozhraní) vypadat následovně:

public class Main {

    public static void output(Dog dog) {
        System.out.println(dog.voice());
    }

    public static void output(Cat cat) {
        System.out.println(cat.voice());
    }

    public static void output(Bird bird) {
        System.out.println(bird.voice());
    }

    public static void main(String[] args) {
        Dog dog = new Dog();
        Cat cat = new Cat();
        Bird bird = new Bird();
        output(dog);
        output(cat);
        output(bird);
    }
}

No, takže máš 3 stejné metody, kterým ovšem předáváš různé parametry, které ale dokonce provolávají stejnou metodu.
Což jaksi není moc efektivní. Teď si představ, že budeš mít takových zvířat dvacet. To budeš pro každého zvířete speciálně definovat novou metodu? (pakliže jo, tak příjemnou zábavu)

Já udělám radši tohle. Definuji nové rozhraní (Animal), které bude předepisovat metodu String voice(). Tuto metodu budou všechny zvířata implementovat.
Díky tomu mi stačí upravit kód v metodě main a místo x stejných metod s různým parametrem bdudu předávat pouze jeden parametr a to společné rozhraní (protože tím všechny ty třídy zjednotím). Takže kód bude vypadat následovně:

public class Dog implements Animal {

    @Override
    public String voice() {
        return "Hafiky haf";
    }
}

public class Cat implements Animal {

    @Override
    public String voice() {
        return "mňau vole au";
    }
}

public class Bird implements Animal {

    @Override
    public String voice() {
        return "kuku";
    }
}

public interface Animal {

    String voice();
}

public class Main {

    public static void output(Animal animal) {
        System.out.println(animal.voice());
    }

    public static void main(String[] args) {
        Animal dog = new Dog();
        Animal cat = new Cat();
        Animal bird = new Bird();
        output(dog);
        output(cat);
        output(bird);
    }
}
Nahoru Odpovědět  +5 24. dubna 16:36
Existují dva způsoby, jak vyřešit problém. Za prvé vyhoďte počítač z okna. Za druhé vyhoďte okna z počítače.
Avatar
Lubor Pešek
Člen
Avatar
Lubor Pešek:24. dubna 16:41

Dále by následovala ukázka výhody abstraktní třídy, ovšem podstatnou výhodu abstrakce sebrala v Javě 7 defaultní metoda, ale na to ses už neptal:)

Jinak má rozhraní v praxi i úlohu takového spojovníka. V podstatě jako kdybys v kódu určoval (předepisoval), do které skupiny bude která class patřit (někdy je to dobré mít něco takového určeného a nezáleží na tom, v jakém balíčku taková třída bude). V podstatě z podobné logiky vychází i různé frameworky, například právě nejvíc populární Spring. DAOčka jsou rozhraní, které je nutno implementovat, ale představují služby, které máš v daném frameworku k dispozici. To, jak si je potom definuješ, to už je na tobě, ale navenek nabídneš pouze rozhraní.

Výše uvedený příklad je takovou typickou ukázkou použití rozhraní. Prostě abys nemusel vytvářet více metod pro stejný případ.

Nahoru Odpovědět  +1 24. dubna 16:41
Existují dva způsoby, jak vyřešit problém. Za prvé vyhoďte počítač z okna. Za druhé vyhoďte okna z počítače.
Avatar
Pluhtík
Člen
Avatar
Pluhtík:24. dubna 20:32

Kolega přede mnou to shrnul pěkně. Ještě bych ale doplnil, že rozhraní má ještě jednu a to ryze praktickou výhodu - dáváš do nich popis metod. I kdyby tak rozhraní implementovala pouze jedna jediná třída, tak ji velice zpřehledníš tím, že místo několik řádků dlouhých popisů každé metody, bude mít většina metod popis přímo v té třídě interface, a v samotné třídě, kde metodu implementuješ, bude pouze @Override.

Dále není příliš neobvyklé (ale ani přikázané), že máš-li tu skupinu tříd, která implementuje jedno rozhraní, tak se snaž nepřidávat do každé třídy další a další veřejné funkce. Spíše se snaž držet jen těch funkcí, co jsou v rozhraní + pomocné privátní funkce, které potřebuješ ke zjednodušení jejich implementace.
Když si vypůjčím příklad se zvířaty tak mohou být metody například zmíněná voice (to ale není moc dobrý příklad, protože argument voice by měl být argumentem třídy a tím pádem ti postačí jednoduchý getter). Představ si například (nějakou složitější) metodu, která při zavolání zjistí, kdy zvíře naposled jedlo, potom zjistí, jak často by mělo jíst a případně jej nakrmí (pokud je to nutné). Rozdělíš to do více funkcí, ale z pohledu uživatele (nebo hráče, protože tohle zní spíše jako hra, že?) tě bude zajímat jen ta jedna jediná, v rámci které, se provedou všechny ostatní. A tak ta jedna jediná bude funkce z interface, budou ji mít všechna zvířata a ty ostatní nikdy nebudeš volat samostatně, nebudeš je smět volat samostatně a hráč/uživatel vlastně ani nebude vědět, že takové funkce existují. Podobně funkce například, kdy bylo zvíře naposled na vycházce.

Vypadat to může nějak takhle

public interface Animal {

        /**
        *
        * zjisti, kdy bylo zvire nakrmeno naposled a pripadne jej nakrmi
        *
        * @return true kdyz zvire bylo nakrmeno, jinak false
        */
        boolean eating();
}

public class Dog implements Animal {
        int lastMealInDays;
        .... other arguments...

        /**
        *
        * konstruktor
        */
        public Dog(arguments...) {}

        @Override
        public boolean eating() {
                implementation...
        }

        /**
        *
        *
        * @return true kdyz zvire bylo nakrmeno, false pokud neni dost zradla
        */
        private boolean feedDog() {
        }
}
 
Nahoru Odpovědět 24. dubna 20:32
Avatar
jip123
Člen
Avatar
Odpovídá na Pluhtík
jip123:25. dubna 16:40

Chlapi, děkuji za podnětné rady. I když frameworks jsou ještě daleko přede mnou :(

 
Nahoru Odpovědět 25. dubna 16:40
Avatar
Lubor Pešek
Člen
Avatar
Odpovídá na jip123
Lubor Pešek:26. dubna 7:45

Ale pokud se to učíš takhle hezky od základu a máš takovéto dotazy (mě se tedy tvůj dotaz líbil:) ), tak jsi na nejlepší cestě, aby ses to naučil.
Vydrž, udržuj ten zájem a všechno to přijde samo. Nakonec poznáš, že programování je sranda a budeš mít obrovskou moc v hlavě:)
(jen ti lidé, co ti budou zadávat úkoly budou mimo:D)

Nahoru Odpovědět  +2 26. dubna 7:45
Existují dva způsoby, jak vyřešit problém. Za prvé vyhoďte počítač z okna. Za druhé vyhoďte okna z počítače.
Avatar
jip123
Člen
Avatar
jip123:26. dubna 16:23

Jsem rád, že jste mně pomohli objasnit základy interfejsů v Javě. Doporučil jsem tyto stránky známému, ale ten se hrabe v PHP.
Nechci tu moc obtěžovat, ale vzhledem k tématu jsem narazil ještě na problém "značkovací interface - marker interface". Už je to trochu vousatý, ale jeho znalost mě láká. Nemohl by sem někdo dát vysvětlení jako Lubor?

 
Nahoru Odpovědět 26. dubna 16:23
Avatar
Petr
Člen
Avatar
Odpovídá na jip123
Petr:3. května 16:53

Marker interface je prazdny interface, kterym oznacis tridu. Potom se pomoci operatoru instanceof muzes dotazat jestli je instance se kterou pracujes oznacena timto interfacem a na zaklade toho udelas nejake rozhodnuti.

Napriklad existuje Serializable interface, ktery rika, ze tridu je mozne serializovat. Samozrejme o serializaci se muzes pokusit u libovolne instance jakekoliv tridy ale ne u kazde to pujde. Kdyz nekdo oznaci tridu timto interfacem tak tim deklaruje, ze je mozne ji bez problemu (de)serializovat.

 
Nahoru Odpovědět  +1 3. května 16:53
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 10.