NOVINKA! E-learningové kurzy umělé inteligence. Nyní AI za nejlepší ceny. Zjisti více:
NOVINKA – Víkendový online kurz Software tester, který tě posune dál. Zjisti, jak na to!
Avatar
Ernest Klonkay:28.2.2016 18:44

Ahojte,

momentalne sa snazim robit aplikacie v OOP aj ked nie su zlozite a nie je potrebne to vyuzivat, no kazdopadne by som sa chcel spytat, ako by moja aplikacia po spravnosti mala vyzerat. Co by som mal zmenit a na co davat pozor?

Main:

package vypoctytelies;

import java.util.Scanner;

public class VypoctyTelies {


    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        double povrch, objem;
        double a, b, c;
        char menu;

        System.out.println("Vypocty Telies");
        System.out.println("Pre vypocty suvisiace s kockou napiste \"1\"\nPre vypocty suvisiace s kvadrom napiste \"2\"");

        menu = (char) Integer.parseInt(in.nextLine());

        if(menu == 1) {
            Kocka kocka = new Kocka();
            kocka.info();
            int volba = Integer.parseInt(in.nextLine());
            if(volba == 1) {
                System.out.println("Zadajte objem");
                objem = Double.parseDouble(in.nextLine());
                kocka.setObjem(objem);
            }
            else if(volba == 2) {
                System.out.println("Zadajte povrch");
                povrch = Double.parseDouble(in.nextLine());
                kocka.setPovrch(povrch);
            }
            else if(volba == 3) {
                System.out.println("Zadajte stranu a");
                a = Double.parseDouble(in.nextLine());
                kocka.setA(a);
            }
            kocka.volbaVypoctu(volba);
            kocka.zobrazHodnoty();
        }

        else if(menu == 2) {
            Kvader kvader = new Kvader();
            System.out.println("Not supported yet");
        }

        else
            System.out.println("Neplatna volba, restartuje aplikaciu");
    }
}

Rozhranie Vzorce:

package vypoctytelies;

public interface Vzorce {

    void setObjem(double o);
    void setPovrch(double p);
    void setA(double sa);
    void setB(double sb);
    void setC(double sc);
    double getObjem();
    double getPovrch();
    double getA();
    double getB();
    double getC();
    void vypocitajObjem();
    void vypocitajPovrch();
}

Trieda Kocka:

package vypoctytelies;

public class Kocka implements Vzorce {

    double objem, povrch, a, b, c;
    boolean maObjem = false, maPovrch = false, maA = false;

    @Override
    public void setObjem(double o) {
        objem = o;
    }

    @Override
    public void setPovrch(double p) {
        povrch = p;
    }

    @Override
    public void setA(double sa) {
        a = sa;
    }

    @Override
    public void setB(double sb) {
    }

    @Override
    public void setC(double sc) {
    }

    @Override
    public double getObjem() {
        return objem;
    }

    @Override
    public double getPovrch() {
        return povrch;
    }

    @Override
    public double getA() {
        return a;
    }

    @Override
    public double getB() {
        return -1;
    }

    @Override
    public double getC() {
        return -1;
    }

    @Override
    public void vypocitajObjem() {
        objem = Math.pow(a, 3);
    }

    @Override
    public void vypocitajPovrch() {
        povrch = 6 * Math.pow(a, 2);
    }

    public void vypocitajA() {
        if(maPovrch)
            a = Math.sqrt(povrch / 6);
        if(maObjem)
            a = Math.cbrt(objem);
    }

    public void info() {
        System.out.println("Co poznate?");
        System.out.println("Stlacte:\n1 - Ak poznate Objem\n2 - Ak poznate Povrch\n3 - Ak poznate stranu a");
    }

    public void volbaVypoctu(int v) {
        int volba = v;
        if(volba == 1) {
            maObjem = true;
            vypocitajA();
            vypocitajPovrch();
        }
        else if(volba == 2) {
            maPovrch = true;
            vypocitajA();
            vypocitajObjem();
        }
        else if(volba == 3) {
            vypocitajObjem();
            vypocitajPovrch();
        }
    }
    public void zobrazHodnoty() {
        System.out.println("Objem je: " + getObjem());
        System.out.println("Povrch je: " + getPovrch());
        System.out.println("Strana a je: " + getA());
    }
}

Este tam su triedy kvader, valec a podobne, ale je to v podstate to iste...

 
Odpovědět
28.2.2016 18:44
Avatar
Robert Michalovič:29.2.2016 7:00

Asi tě zklamu, ale nikde jsem si nevšiml, že bys používal OOP(zapouzdře­ní,dědičnost a polymorfismus). Používání objektů(instance) není OOP(orientované objektové programování).

 
Nahoru Odpovědět
29.2.2016 7:00
Avatar
Odpovídá na Robert Michalovič
Ernest Klonkay:29.2.2016 14:18

Ako by to teda po spravnosti malo vyzerat s pouzitim OOP? Ako som pisal som zaciatocnik a snazim sa pouzivat "OOP"

 
Nahoru Odpovědět
29.2.2016 14:18
Avatar
Robert Michalovič:1.3.2016 7:23

OOP (3 pilíře OOP):
1 - zapouzdření ( použití modifikátoru přístupu v třídách např. public,protec­ted,private, + getter/setter)
2 - dědičnost ( použití dědičnosti - tvz. extends )
3 - polymorfismus ( použití polymorfismu přes dědičnost nebo rozhraní )

Projdi si tu tutoriály, nejsou špatné ( http://www.itnetwork.cz/…olymorfismus) a ( http://www.itnetwork.cz/…tery-settery ) a pak teprve přemýšlej jak využít OOP. Existují úlohy ve, kterých se všechny pilíře OOP prostě nevyužijí.

  1. class Kocka - zde máš spoustu setterů/getterů ale jsou k ničemu neboť k proměnným v třídě je umožněn přístup.

private double objem, povrch, a, b, c;
private boolean maObjem = false, maPovrch = false, maA = false;
... toto je správně využití 1. pilíře tvz. zapouzdření

  1. Protože v příkladu máš jenom objekt Kocka pak prakticky nemůžeš využít dědičnost.

Kdybys měl třídu class Zvire a pak class Kocka extends Zvire pak toto je příklad dědičnosti
... toto je správně využití 2. pilíře tvz. dědičnosti

  1. Polymofismus ve svém příkladu nemůžeš využít k tomu je potřeba vice typu např. Kocka,Pes, Krava buď děděných od Zvire nebo obsahující nějaké rozhraní např. interface Vzorce.
 
Nahoru Odpovědět
1.3.2016 7:23
Avatar
Atrament
Člen IT Redactor Gang
Avatar
Odpovídá na Ernest Klonkay
Atrament:1.3.2016 10:49

Koukám, že kolegu výše taky zmátla ta 'Kocka' - taky jsem hezkých pár chvil přemýšlel, co tam dělá Kočka (slovensky Mačka) mezi těmi kvádry a tělesy :)

Objektově orientovaný přístup je především postaven na tom, že modeluješ logiku aplikace tak, aby její součásti (třídy, moduly, balíčky,...) co nejvíce odpovídaly modelu realného světa. S tím souvisí i vztahy mezi těmito součástmi - taky by měli co nejvíce odpovídat těm v reálném světě. Pokud máš třídu Kocka co implementuje nějaký interface Vzorce, tak na první pohled vidíš že to spolu moc nesouvisí, copak Kocka obsahuje nějaké Vzorce?

Ve tvém případě modeluješ Tělesa u nichž tě zajímají Obsah a Povrch. Každé Těleso má nějaké rozměry a u každého se dá spočítat jeho Obsah a Povrch, existují ale různé druhy Teles s různými rozměry a různými metodamy jak vypočítat jejich Obsah a Povrch.

Pro vyjádření této situace se obvykle používá dědičnost. Máš třídu Teleso a pak další třídy jako Kocka, Valec, Kvadr atd, které od té třídy Teleso dědí nejaké základní společné rysy. V Tělese budeš mít abstraktní metody pro výpočty, které potom konkrétně implementuješ v těch potomcích. Smysl je v tom, že pak budeš moct udělat něco takového:

Teleso kocka = new Kocka(10); //tvorime kocku o velikosti strany 10
Teleso kvadr = new Kvadr(10,20,30) // tvorime kvadr o velikostech stran 10, 20, 30

System.out.println("Kocka ma obsah: " + kocka.getObsah());
System.out.println("Kvadr ma obsah: " + kvadr.getObsah());

Všimni si, že v obou výpisech jsem použil stejnou metodu getObsah() a vůbec mě nezajímalo jestli jde o kocku nebo kvádr.

 
Nahoru Odpovědět
1.3.2016 10:49
Avatar
mayo505
Tvůrce
Avatar
Odpovídá na Ernest Klonkay
mayo505:1.3.2016 11:17

Ako už písali vyššie, to rozhranie moc nedáva zmysel, je príliš veľké. Porušuje to interface segregation principle, ktoré hovorí, že nemáš mať veľké rozhrania, lebo ťa to núti implementovať aj veci ktoré nepotrebuješ (napríklad setB, setC) ... tým pádom to poruší aj liskov substitution principle, ktorý hovorí síce hovorí o tom, že tam kde sa očakáva nadtrieda môže byť použitá podtrieda, ale platí to aj pre interfaci. Ak niekde očakávaš interface Vzorce a budeš využívať všetky jeho možnosti (teda setA, setB, setC s rôznymí číslami) poruší ti to logiku tej kocky. Kvôli tomuto by som bol veľmi opatrný aj s dedičnosťou.

Ďalej funkcie ako setObjem a setPovrch ti porušujú zapúzdrenie a neviem si predstaviť čo to spraví u kvádru (vznikne nekonzistentnosť pretože, dĺžky strán nebudeš vedieť a aj tak môžeš použiť tú funkciu).

Funkcie vypocitajObjem a vypocitajPovrch sú zbytočné, stačí ti getObjem a getPovrch a tam urobiť výpočet

Funkcia info, nemá čo v triede Kocka robiť

Funkcia volbaVypoctu je tiež veľmi divná.

Čiže ako by sa to dalo spraviť? V rozhraní nechať len funkcie getObjem() a getPovrch(). Objekt Kocka by mal fungovať ako skutočná kocka, čiže napr. bez funkcií setB() a bez funkcií ktoré s kockou nemajú nič spoločné napr. info. Navyše kocku by som vytváral už asi parametrom v konštruktore (bez setA), JavaBeany sú trochu kontroverzné, pretože máš nekonzistentný stav (síce len pár riadkov, ale máš kocku bez strany)

 
Nahoru Odpovědět
1.3.2016 11:17
Avatar
Ernest Klonkay:11.3.2016 9:35

Bol som tyzden mimo, tak skusil som to vylepsit alebo resp. prerobit podla vasich rad. Dufam, ze tentokrat uz to je lepsie, bol by som rad, ak by mi to niekto zhodnotil.

package vypoctytelies;

import java.util.Scanner;


public class VypoctyTelies {

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        double povrch, objem;
        double a, b, c;
        int menu, menukocka, menukvader;

        System.out.println("VÝPOČTY TELIES");
        System.out.println("Zvolte teleso:\n1 <- Kocka\n2 <- Kváder");

        menu = Integer.parseInt(in.nextLine());

        if(menu >= 1 && menu <= 2) {
            if(menu == 1) {
                System.out.println("Vybrali ste si kocku");
                System.out.println("Zvolte výpočet:\n1 <- Poznám stranu a\n2 <- Poznám objem\n3 <- Poznám povrch");

                menukocka = Integer.parseInt(in.nextLine());

                if(menukocka >= 1 && menukocka <= 3) {
                    if(menukocka == 1) {
                        System.out.println("Zadajte stranu a");
                        try {
                            a = Double.parseDouble(in.nextLine());
                            Tvary3D kocka = new Kocka(a);
                            System.out.println("Strana a je: " + kocka.getStranuA());
                            System.out.println("Uhlopriečka je: " + kocka.getUhlopriecka());
                            System.out.println("Povrch je: " + kocka.getPovrch());
                            System.out.println("Objem je: " + kocka.getObjem());
                        }
                        catch(NumberFormatException ex) {
                            System.out.println("Nezadali ste číslo!");
                            System.out.println(ex.getMessage());
                        }
                    }
                    else if(menukocka == 2) {
                        System.out.println("Zadajte objem");
                        try {
                            objem = Double.parseDouble(in.nextLine());
                            Tvary3D kocka = new Kocka();
                            kocka.setObjem(objem);
                            System.out.println("Strana a je: " + kocka.getStranuA());
                            System.out.println("Uhlopriečka je: " + kocka.getUhlopriecka());
                            System.out.println("Povrch je: " + kocka.getPovrch());
                            System.out.println("Objem je: " + kocka.getObjem());
                        }
                        catch(NumberFormatException ex) {
                            System.out.println("Nezadali ste číslo!");
                            System.out.println(ex.getMessage());
                        }
                    }
                    else if(menukocka == 3) {
                        System.out.println("Zadajte povrch");
                        try {
                            povrch = Double.parseDouble(in.nextLine());
                            Tvary3D kocka = new Kocka();
                            kocka.setPovrch(povrch);
                            System.out.println("Strana a je: " + kocka.getStranuA());
                            System.out.println("Uhlopriečka je: " + kocka.getUhlopriecka());
                            System.out.println("Povrch je: " + kocka.getPovrch());
                            System.out.println("Objem je: " + kocka.getObjem());
                        }
                        catch(NumberFormatException ex) {
                            System.out.println("Nezadali ste číslo!");
                            System.out.println(ex.getMessage());
                        }
                    }
                }
                else
                    System.out.println("Neplatný výber!");
            }
        }
        else
            System.out.println("Neplatný výber!");
    }
}

.

package vypoctytelies;

public abstract class Tvary3D {

    protected double objem, povrch;

    public double getObjem() {
        return objem;
    }

    public void setObjem(double obj) {
        objem = obj;
    }

    public double getPovrch() {
        return povrch;
    }

    public void setPovrch(double povr) {
        povrch = povr;
    }

    abstract double getUhlopriecka();
    abstract double getStranuA();
}

.

package vypoctytelies;


public class Kocka extends Tvary3D {

    private double a;

    public Kocka(double sA) {
        a = sA;
    }

    public Kocka() {

    }

    @Override
    public double getPovrch() {
        return (6 * a * a);
    }

    @Override
    public double getObjem() {
        return (a * a * a);
    }

    @Override
    public double getUhlopriecka() {
        return (a * Math.sqrt(2));
    }

    @Override
    public double getStranuA() {
        return a;
    }
}
 
Nahoru Odpovědět
11.3.2016 9:35
Avatar
Robert Michalovič:12.3.2016 5:27

Jo, to už je použítí OOP v praxi.Používáš dědičnost a zapouzdření a nepředvádíš tvz. "programování s objekty". K plnému OOP už jen chybí dodělat polymorfismus(přes dědičnost nebo rozhraní).

 
Nahoru Odpovědět
12.3.2016 5:27
Avatar
mayo505
Tvůrce
Avatar
Odpovídá na Ernest Klonkay
mayo505:13.3.2016 17:42

Je to lepšie ale stále mi to nedáva na 100% zmysel. Keď máš abstraktnú triedu Tvary3D (mimochodom, mala by sa volať Tvar3D), očakávaš, že každý jej potomok bude použiteľný namiesto nej. To ale nie je úplne pravda. Čo ak budeš mať nejaký superdivný 3D tvar, vytvoríš z neho objekt a u neho nemajú zmysel funkcie ako getUhlopriecka(), getStranuA(). Alebo napríklad taký štvorsten, ten asi ani nemá uhlopriečku (aj ak má tak je to strana).

Podľa mňa ti dedičnosť neprináša žiadne výhody (teda okrem toho, že nemusíš písať funkciu setObjem a setPovrch znova ale to je zlé použitie dedičnosti) a podľa mňa tu ani nemá význam (resp. nie takto).

Robertov komentár tiež nedáva zmysel, zapúzdrenie tu skoro ani nemáš, keďže môžeš kedykoľvek zmeniť objem. Keď potrebuješ vytvárať objekty z objemu a povrchu (čo je samo o sebe divné a v minime 3D tvarov to má význam) radšej by som to robil nejakou factory metodou napr.

Kocka kocka = Kocka.vytvorZObjemu(objem)

Takisto neplatí, že ak použiješ dedičnosť, zapúzdrenie a polymorfizmus hneď máš super OOP a keď nie tak nie (mimochodom povedal by som, že aký taký polymorfizmus v tomto prípade existuje).

 
Nahoru Odpovědět
13.3.2016 17:42
Avatar
Robert Michalovič:14.3.2016 6:46

"Robertov komentár tiež nedáva zmysel, zapúzdrenie tu skoro ani nemáš, keďže môžeš kedykoľvek zmeniť objem. Keď potrebuješ vytvárať objekty z objemu a povrchu (čo je samo o sebe divné a v minime 3D tvarov to má význam) radšej by som to robil nejakou factory metodou napr."

A co je tohle?

public class Kocka extends Tvary3D {
    private double a;

zapouzdření není jenom o použití "private". I když je pravda že pokud je proměnná "protected" a třídy jsou ve stejném balíčku tak tím nic nezapouzdří.

public abstract class Tvary3D {
    protected double objem, povrch;

Pointou je pochopení principů OOP, nikoliv provádění OOA či OOD čehož je důkazem i název tématu.

 
Nahoru Odpovědět
14.3.2016 6:46
Avatar
mayo505
Tvůrce
Avatar
Odpovídá na Robert Michalovič
mayo505:14.3.2016 12:32

Napísal som "skoro", nie, že "vôbec". A ako vravíš zapúzdrenie nie je len o používaní private. Síce má "zapúzdrený" atribút a, na druhej strane ale umožňuje nastaviť a zmeniť atribút objem. Príklad

Kocka kocka = new Kocka(5);
kocka.setObjem(1000) // v tomto momente a = 5, objem = 1000

Konkrétne v tomto prípade u kocky je povedzme to zapúzdrenie ako tak dodržané, na vonok sa tvári konzistentne (aj keď vo vnútri nie je) a to preto lebo prepísal funkciu getObjem(), tak sa ospravedlňujem za silnejšie slová. Ale ak vytvorí novú triedu tam to už nemusí dodržať.

Mimochodom nechápem ako môže tento kód fungovať

objem = Double.parseDouble(in.nextLine());
Tvary3D kocka = new Kocka();
kocka.setObjem(objem);
System.out.println("Strana a je: " + kocka.getStranuA());
System.out.println("Uhlopriečka je: " + kocka.getUhlopriecka());
System.out.println("Povrch je: " + kocka.getPovrch());
System.out.println("Objem je: " + kocka.getObjem());

Keď všetky tie funkcie u kocky pracujú s atribútom "a", ktorý nie je nikde nastavený

Editováno 14.3.2016 12:34
 
Nahoru Odpovědět
14.3.2016 12:32
Avatar
coells
Tvůrce
Avatar
Odpovídá na mayo505
coells:14.3.2016 13:08

Máš pravdu a zapouzdření tam vůbec není, žádné skoro.
Je to typická ukázka "programování s objekty".

Pod to, co jsi psal včera, bych se klidně podepsal s výjimkou factory metod.
To je obezlička v Javě, která řešit nepříjemnosti s chybějícím polymorfismem inicializérů.

 
Nahoru Odpovědět
14.3.2016 13:08
Avatar
mayo505
Tvůrce
Avatar
Odpovídá na coells
mayo505:14.3.2016 13:44

dik ... ako by potom konkrétne vyzeralo to vytvorenie objektu z objemu? Nejaký stručný príklad

 
Nahoru Odpovědět
14.3.2016 13:44
Avatar
coells
Tvůrce
Avatar
Odpovídá na mayo505
coells:14.3.2016 18:20

V Javě tak, jak jsi napsal.
V dynamických jazycích mám radši class clusters než factory, kód je přirozenější a umožňuje polymorfismus.
V OOP bych se zamyslel nad tím, že míra a povrch mohou být také objekty, ale na takových vyumělkovaných příkladech se cokoliv špatně vymýšlí.

 
Nahoru Odpovědět
14.3.2016 18:20
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 14 zpráv z 14.