Diskuze: Výpočet obvodu a obsahu
V předchozím kvízu, Online test znalostí Java, jsme si ověřili nabyté zkušenosti z kurzu.


Jindřich Máca:5.12.2017 1:32
Ahoj, je to docela jednoduché. V těch jednotlivých case
uděláš následující:
...
case 1:
...
double stranaB = scanner.nextDouble();
Obvod obvod = new Obvod(stranaA, stranaB);
obvod.vypocitejObvod();
strany.add(obvod);
...
case 2:
...
double stranaB = scanner.nextDouble();
Obsah obsah = new Obsah(stranaA, stranaB);
obsah.vypocitejObsah();
strany.add(obsah);
...
Jinak bych Tě chtěl ještě upozornit, že ten kód je koncepčně úplně
špatně, hlavně z hlediska OOP... Měl jsem zrovna chvíli i náladu a tak
jsem to zkusil v rychlosti napsat, jak bych to asi řešil já. Tady najdeš
zdrojové kódy - https://www.itnetwork.cz/dev-lighter/992 Zkus si to projít a
kdyby nebylo něco jasné, klidně se ještě ptej.
Děkuji, pomohlo mi to a už to jde.
Vím, že kód asi nebude nic moc, ale mám Javu první semestr a tohle je
vůbec první kód, který jsem psala.
Malinká poznámka k Jindrovému kódu (tam to nejde připsat, tak to píšu
sem)
Čtverec je speciální případ obdelníka. Můžeš to tedy podědit.
// Soubor Ctverec.java
class Ctverec extends Obdelnik {
public Ctverec(double size) {
super(size, size);
}
@Override
public TypGeometrickehoTvaru typObrazce() {
return TypGeometrickehoTvaru.CTVEREC;
}
}
Nicméně jinak bych nic neměnil (a tohle je stejně jen malá drobnost), hezký kód
Neználek:5.12.2017 21:28
Následující kód je špatně:
class Ctverec extends Obdelnik
Doporučuji poslechnout si Roberta Martina:
https://youtu.be/TMuno5RZNeE?…
Čtverec je sice speciální případ obdélníka. To ale neznamená, že by třída Ctverec měla být potomkem třídy Obdelnik.
Lubor Pešek:6.12.2017 7:04
Přiznám se, že toho člověka neznám a co jsem viděl to video a trochu
jsem si o něm přečetl, tak jsem zjistil, že ho ani znát nepotřebuju (už i
ty komentáře o něčem trošku svědčí)
Takže abych si to shrnul - on tvrdí, že třída Obdelník není skutečný
obdelník, ale kód, který představuje obdelník (a to samé u třídy
Čtverec). A já blbec si pořád myslel, že hlavním důvodem, proč vůbec
nějaké OOP vzniklo, je abychom se na všechny subjekty, které programujeme,
dívali jako na objekty.
Očividně je to asi naopak.
Peter Sciranka:6.12.2017 12:51
Ahoj, tak som si pozrel to video a myslím, že stojí za pozretie. On
vysvetľuje "SOLID" design a jednotlivé princípy a čo sa týka toho štvorca
a obdĺžnika, tak v jeho príklade je porušený princíp "L" (Liskov
substitution principle).
V tvojom konkrétnom príklade ten princíp nie je porušený, ale myslím, že
poukázal na zaujímavú vec:
- štvorec by nemal byť "principiálne" potomkom obdĺžnika a to kvôli tomu, že na definovanie obdĺžnika nutne potrebuješ dve hodnoty, na štvorec len jednu.
- dedičnosť je o tom, že potomok implementuje (z principiálneho pohľadu sú pre neho potrebné) všetky atribúty a metódy rodiča, ale v tomto prípade to tak nie je, pretože štvorec nepotrebuje 2, ale len 1 atribút (úspora 50%). Samozrejme v tomto príklade sa to môže zdať ako zbytočnosť, ale jedná sa skôr o pochopenie princípu a následné vytváranie dobrého designu.
Čo sa týka toho, že spomína, že obdĺžnik nie je skutočný obdĺžnik, tak to sa práve snaží vysvetliť to, že napr. class auto (a jeho inštancia) nie je skutočné reálne auto, ale len jeho reprezentácia v tvojom kóde a tým pádom by si mal prispôsobiť ten kód tomu, aby fungoval čo najlepšie v tvojej aplikácii (bude nasledovať určité princípy):
- trochu to preženiem, ale do svojej triedy "auto" neimplementuješ napr. atribút "poťah sedadiel", ak ho nikdy nikde nevyužiješ (aj keď dané reálne auto má nejaké sedadlá).
- tak isto asi nebudeš dediť triedu "auto" z triedy "lietadlo", aj keď všetko, čo môžeš robiť s autom, môžeš robiť aj s lietadlom a tým pádom je auto špeciálny druh lietadla a to také, ktoré nelieta. Tak toto je myslím zlý príklad dedičnosti ale dobrá paralela k štvorcu a obdĺžniku.
Takže obdĺžnik a štvorec sa môže dediť z triedy "geometrickýTvar", tak ako aj lietadlo a auto sa môže dediť z triedy "dopravnýProstriedok", to myslím dáva väčší zmysel.
PS: Nerobím si žiadny nárok na pravdu a ak sa mýlim, alebo je moja úvaha
nesprávna, tak budem vďačný, ak ma na to upozorníte
Lubor Pešek:6.12.2017 13:33
jo, krásně jsi tu popsal, kdy využít a nevyužít dědičnost:) Jasně, že je nebezpečné, pokud se dědičnost používá všude možně. Proto se musí (takto, jak jsi to popsal) takhle předem uvažovat, kdy je to vhodné a kdy ne. V tomto s tebou souhlasím. Nejznámější příklad je toho programátora, který řešil problém mezi cyklistou a žábou. Oba se mohli pohybovat. Ale když se dostal ke kamenům, po kterých cyklista nemohl přejet, ale žába mohla přeskákat, tak to programátor řešil tak, že cyklista dědil od žáby. Potom bylo úsměvné, že cyklista podědil i metodu kvákej.
Takže s tebou maximálně souhlasím - se vším, co jsi psal. A ano, na obdelník i čtverec se dá pohlížet jako na rozdílné útvary. Toto beru.
Nicméně jedno to ale si neodpustím:)
Ale vzpomeň si na základní školu - od základky se učíme, že právě ten
nešťastný čtverec je speciálním případem obdélníka. Ano, z tohoto
pohledu, co tu propagoval ten "profesor", tak on si to může touhle teorií
vysvětlit i takto.
Nicméně ty když dědíš z nějaké třídy, tak využíváš bez výjimky
všechny předkovi metody? To by dědičnost ztrácela tak trošku smysl -
stačilo by vždycky jen a jen rozšiřovat předka.
A to, že čtverec místo dvou metod zavolá jednu (ve které může klidně
zavolat obě předkovi metody), například takhle:
public void setSize(int size) {
super.setWidth(size);
super.setHeight(size);
//nebo pokud by byla metoda setSize(int, int)
super.setSize(size, size);
}
Jinak jaké má čtverec vlastnosti, které nemá obdélník? to že tomu
lidé říkají jinak, že to nějak specializují, tak to je náš problém
(třeba, že čtverec má úhlopříčky stejně velké).
Kdyby to byl jiný případ, určitě stejně jako ty, budu dlouze přemýšlet
nad dědičností. Ale tady si nejsem vědom jakéhokoliv nebezpečí, proč
bych neměl dědit. Toto je spíš krásný důkaz, že jeho teorie má chybu.
Protože se nedá nic zkazit. Pokud ano, prosím aspoň o jeden případ, kdy
dojde k nějakému nesmyslu a já to uznám.
Peter Sciranka:6.12.2017 15:12
Ďakujem za komentár
Nemyslím si, že ty si urobil nejakú chybu, alebo porušil nejaký princíp. To ako píšeš, tak máš pravdu a nemyslím si, že je to v niečom nebezpečné, ale taktiež si nemyslím že on vraví nejaké hlúposti.
Ja viem že pôvodne si to napísal ako rekciu na zadaný príklad, poukázal
si na dedičnosť a jej praktické využite a je dobre že si tak urobil, tak
ďalší text ber prosím už len skôr ako také zamyslenie.
Čo sa týka všeobecne štvorca a obdĺžnika, ako aj sám píšeš, štvorec
nemá žiadne iné metódy a atribúty ako trieda obdĺžnik, takže v podstate
je zbytočné vytvárať dedičnú triedu štvorec, pretože stačí v
konštruktore zadať obe hodnoty ako "size", "size" a tým pádom nemá zmysel
dediť triedu, ak sa v ničom nelíši od rodiča.
- Jedine, že by sme niekde v kóde zisťovali, či je daný objekt inštanciou štvorca alebo obdĺžnika, ale tam je už potom na zamyslenie, či štvorec mať ako geometrickýTvar alebo ako podedený obdĺžnik.
PS: Ja sa každopádne stále učím a snažím sa pochopiť pohľad a postoj
iných (hlavne tých chytrejších ľudí), tak ako toho pána vo videu tak aj
ten tvoj a som ti zaňho vďačný
Nestacilo prostě nalinkovat circle-ellipse problém?
https://en.wikipedia.org/…ipse_problem
Neználek:6.12.2017 19:51
Díky moc za podnět k přemýšlení.
Pro jistotu přidávám celý kód, ať je jasné, o čem se bavíme.
public class Rectangle {
private int width;
private int height;
public Rectangle(int width, int height) {
super();
this.width = width;
this.height = height;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
}
Jak bys naprogramoval metodu getSize?
public class Square extends Rectangle {
public Square(int size) {
super(size, size);
}
public void setSize(int size) {
super.setWidth(size);
super.setHeight(size);
}
public int getSize() {
/* ??? */
}
}
Lubor Pešek:6.12.2017 20:57
Tak když už se tu bavíme o naprosté dokonalosti, tak ok...
- nechápu proč voláš konstruktor třídy Object. Jestli to má nějaký hlubší význam, to mě když tak taky pouč.
- bavíme se tu o tvarech, že? Tak proč určuješ, že bude první parametr šířka a druhý výška? já třeba budu chtít, abych měl jako první parametr výšku. Tudíž si volím víc obecnější pojmenování (tak jak to známe) "a" a "b". No a protože neuznávám krátké názvy, tak to můžem nazvat třebas "sideA" a "sideB".
public class Rectangle {
private int sideA;
private int sideB;
public Rectangle(int newSideA, int newSideB) {
sideA = newSideA;
sideB = newSideB;
}
public int getSideA() {
return sideA;
}
public void setSideA(int newSideA) {
sideA = newSideA;
}
public int getSideB() {
return sideB;
}
public void setSideB(int newSideB) {
sideB = newSideB;
}
}
A odpověď na tvou otázku? stejně, jako bych ti odpověděl v matematice. "Čtverec má stranu a"
public class Square extends Rectangle {
public Square(int newSideA) {
super(newSideA, newSideA);
}
@Override
public void setSideA(int newSideA) {
super.setSideA(newSideA);
//nevím, proč nastavovat v takovémto kódu straně B stranu A.... trošku nelogické.
}
@Override
public int getSideA() {
//čoveče nebudeš tomu snad ani věřit, ale...
return super.getSideA();
}
}
Abych to shrnul, já se vyjadřuju celou dobu k tomuto topicu a ke kódu, jak
by se dal ještě trošku usnadnit. V tomto konkrétním případě je to
právě možné. Tím nezpochybňuji to, co bylo řečeno a souhlasím s tím,
že je třeba se vždycky velmi dobře zamyslet, kdy je dědičnost vhodná a
kdy ne (jak z programátorského hlediska, tak i z logiky věci). Tento
konkrétní případ se dá vyložit očividně několika způsoby. Mě prostě
strýček bob nebo jak mu říkají nepřesvědčil a nevyvrátil to, co
říkám. Myslím tím, že bych tímto mohl program jakkoliv v budoucnu
ohrozit. Já v tom vidím jen usnadnění práci, protože (a sorry, to mi nikdo
nevyvrátí) čtverec je a vždycky bude speciálním případem obdélníku,
který můžeme ještě nějak specifikovat, ale nemění se nic na tom, že se
čtverec bude vždycky chovat jako obdélník (jestli existuje nějaký
případ, kdy ne, tak sem s ním, rád se přiučím a bude-li to faktické, tak
rád uznám jinou teorii)
Pro mě je tento člověk prozatím důkazem, že se hodně nudí a přemýšlí
o blbostech. A to, že on přijde s nějakou teorií, tak to není pro mě
důvod, abych popřel to, co používám celý život, to se na mě nezlob.
Naopak on by se měl asi zamyslet nad tím, že právě existují i některé
případy, které jeho teorii podkopávají.
Já třeba maximálně uznávám Martina Fowlera, ale taky ne ve všem. Je to
prostě individuální a záleží na člověku, jak se na danou problematiku
dívá - viz naše dva kódy. Oba dělají naprosto totožnou věc, ale ty se na
to díváš z revolučního pohledu, já z konzervativního. To ale fakt
neznamená, že v jiném případě budu postupovat stejně. Kdyby to tak mělo
platit, tak není třeba programátorů, ale stačilo by právě jednorázově
naprogramovat robota a ten by sypal jeden stejný kód podle jedné teorie a
praktiky za druhým.
Tímto prosím o ukončení této debaty, protože to nikam nevede. Já téhle
teorii prostě nechci rozumět, protože v ní nevidím smysl, Ty a mnozí
další v tom vidíte budoucnost. Jediné, k čemu by to směřovalo, tak by
byly nakonec nějaké osobní narážky a urážky. A IT network není
parlament, ale skvělý český portál, kam toto nepatří. Takže za mě
dobrý, díky za diskuzi, ale dál se vyjadřovat nebudu, chci si Tě spíš
vážit, než se tu s Tebou přít.
Neználek:6.12.2017 21:56
Z tvých reakcí mám dojem, že reaguješ na něco, co jsem vůbec neřekl.
Snažil jsem se pouze upozornit na chybu v návrhu. Čirou náhodou jsem nedávno viděl video Roberta Martina a tak jsem přidal odkaz, to je vše.
K tvým otázkám
- super() do konstruktoru mi doplnilo IDE a nevadí mi. Pokud bych ho tam neuvedl, doplnil by ho kompilátor. Byte kód bude v obou případech stejný, protože v Javě se konstruktor předka volá vždy.
- Snažil jsem se napsat kód tak, jak jsem ho pochopil z tvých komentářů, abych se vyhnul nedorozumění. Obě varianty width/height a sideA/sideB jsou samozřejmě možné. Záleží na kontextu a konkrétním použití.
- Pro mě osobně je tato debata přínosná, protože mi ukazuje, jak uvažují ostatní lidé. Rozhodně nemám v úmyslu nikoho urážet ani napadat.
- Tvůj kód je špatně, protože dovoluje napsat následující nesmysl:
Square square = new Square(10);
square.setSideA(10);
square.setSideB(20);
gcx11:6.12.2017 22:08
Ale jinak je tam celkem zbytečný. Taky nebudeš psát pro každé volání funkce proměnnou, do které uložíš výsledek volání, stejně tak s iterátory, přestože to kompilátor stejně udělá.
Zobrazeno 14 zpráv z 14.