Životní dilema - architektura aplikace v Javě – Java – Fórum – Programujte.com
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

Životní dilema - architektura aplikace v Javě – Java – Fórum – Programujte.comŽivotní dilema - architektura aplikace v Javě – Java – Fórum – Programujte.com

 

Mufik0
Duch
29. 1. 2016   #1
-
0
-

Zdravím,

 pomozte mi, znalí věci a zkušení, vyřešit mé životní dilema architektury aplikace v Javě.

Uvedu svůj dotaz na praktické situaci:

Jsem rozmazlený z knihovny Qt: když chci založit Socket server, prostě jen vytvořím novou třídu s portem na kterém se bude naslouchat, a ONO UŽ TO BĚZÍ. Jakákoliv interakce s tímto objektem je už pak přes signály a sloty. Příjde nové připojení? Vyvolá se událost. Příjde nový paket?Vyvolá se událost. Chci zastavit server? Vyvolám z nějakého objektu signál připojený na jeho slot. Architektura aplikace je jasně daná, vše je přehledné, můžu hned začít psát aplikaci kterou chci a nemusím zbytečně přemýšlet nad přehršelem možností jak něco "zbastlit".

Ovšem Java ve mně evokuje chaos. Chtěl bych psát čistě událostmi řízené aplikace, ale třídy v Javě nejsou k tomu uzpůsobeny, neboť používají se vyláním jejich metod. Např. založím-li si třídu Server, ve které pracuji se ServerScoket, musím ji spustit v samostatném vlákně, a v té třídě budu ústavičně v nějakém Whiilu zkoumat, zda něco nového nepřišlo, a následně tuto třídu spustit ve vlákně.

Jistě, mohu si psát vlastní třídy, kde veškeré interakce mezi nimi budou přes události, ale v Javě mi to příjde jako narovnávák na ohýbák, nehledě na to, že Java nemá v jazyce implementovánu přimou podporu pro eventy. (jinak, než-li přes implementaci NV Observer).

To ve mně vyvolává dilema: chci psát aplikaci, kde jednotlivé celky jsou zapouzdřeny ve smyslu OOP a jedná se o samostatně pracující jednotky, jako v Qt, jenže zároveň se do nich musím ústačně "dobývat", chapete-li mně, voláním jejich metod, často v mnou napsaném whilu. Jistě, je zde způsob: napsat každou třídu tak, že bude běžet v samostatném vlákně, jenže to domnívám se bude katastrofa  hlediska výkonostního.

Prostě tento způsob Javího programování nevyvolává ve mně to, co bych si představoval od OOP, spíše bych to považoval takové napůl OOP a napůl procedurální programování.

Chápete-li, co chci říct, poraďte, jak se v tomto zorientovat, zdaž-li neznáte k tomu nějaký vhodý best-practice příklad Díky

Nahlásit jako SPAM
IP: 90.179.206.–
m4r100
Návštěvník
30. 1. 2016   #2
-
-2
-
Mimo téma

#1 Mufik
Pokud se chces min trapit, mit podporu od jazyka, mit prehlednejsi a cistejsi kod prejdi na C#. V Jave neni budoucnost.. 

Nahlásit jako SPAM
IP: 37.188.233.–
Mufik
~ Anonymní uživatel
6 příspěvků
30. 1. 2016   #3
-
0
-

#2 m4r10
To je pěkná hloupost co tvrdíš, v Javě je budoucnost přinejmenším ještě do mého důchodu. Navíc .NET kolem a kolem kompletně znám, a přešel jsem na Javu.

Nahlásit jako SPAM
IP: 90.179.206.–
Kit+15
Guru
30. 1. 2016   #4
-
0
-

#2 m4r10
C# si natahal do syntaxe příliš mnoho nešvarů z céčka. K tomu tam ještě nadělal nesmyslné gettery a settery, které jsou nyní vývojáři hojně zneužívány. V konečném důsledku zapomínají na SOLID a vlastně i celé OOP.

Nahlásit jako SPAM
IP: 194.228.68.–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
Mufik
~ Anonymní uživatel
6 příspěvků
30. 1. 2016   #5
-
0
-
Nerozhodně
Kit +

No co bych já C# vytknul, tak multiplatfmormnost 0, nerozjedeš to na Linuxu, což je zásadní nevýhoda u informačních systémů, cena - hodně lidí má rádo C# a osobně se domnívám, že nějak zapomínají na ty peníze, co za něj musíš dát, příčemž tím to nekončí, pokud ho chceš nasadit na server, tak ještě hezky zacáluješ Windows Server, spousta knihoven pro C# je rovněž placených (já mám zkušenost s knihovnou pro grafy (teda, nemám, nechtělo se mi za to uvalit 1000,- ) ).

Takže C# vs Java - vede u mě Java. na otázku jaký je nejlepší prog jazyk ale říkám: C++/Qt :-)

Nahlásit jako SPAM
IP: 90.179.206.–
m4r100
Návštěvník
30. 1. 2016   #6
-
0
-

#5 Mufik

1000Kc? Pro kazdou normalni firmu nulove naklady.

.NET a multiplatformnost: 

Java je nemoderni jazyk, ve kterem je utrpeni pracovat. Pred nedavnem jsem neco delal v Jave, nutne jsem potreboval nejaky ekvivalent k Func<T1, T2>, Action<T> z C#, abych mohl doimplementovat uplne zakladni callback pro asynchronni metody. Neni, tato funkcionalita v Jave uplne chybi (musi se pouzit interni anonymni tridy, hrozne..)!

Eventy - nejsou... 

LINQ (rok 2007) oproti Java 8 (2015) - kdyz uz zaspali dobu o 8 let, aspon to mohli doimplementovat poradne, aktualne se to pouziva o hodne hure nez LINQ. Viz nize.

Eclipse vs Visual Studio?? Bez komentare... Clovek si musi pekne priplatit v Jave aby mel nejake rozumne IDE (Intelij).. V .NET je zvykem, ze si stahnu kod z Github, zmacku F5 a vsechno funguje (vcetne DB, web serveru, atd...). Pokud bych toto udelal v Eclipse s Java kodem, pak na mne prinejlepsim vyskoci jenom par erroru, ale stejne cely den budu zjistovat co potrebuji jeste v tom konfiguracnim/nastavovacim pekle zmenit aby se to rozjelo... 

Vlastnosti jazyka C# jsou uz daleko pred Javou a bude hur.. C# 7 nejspise prijde z immutable tridama - na to se nemuzu dockat, konecne konec s null "hodnototu". 

Jasne Java tady bude jeste hodne dlouho, ale pokud nekam nastoupis pracovat, pak budes spravovat nejake obskurni enterprise systemy s miliony radku kodu. Cely den budes mit zapnuty debugger a budes hledat to jedine misto kde je treba dopsat pul radku kodu abys splnil dalsi task s novou funkcnosti. Prace, kterou nikdo nechce delat. 

#4 Kit
Nasledovani syntaxe C jazyku neni na skodu, lidem se to bude jednoduseji ucit a tim se zajisti vetsi komunita.

Mas pravdu, ze gettery a settery svadi k necistemu kodu, ale vsechno to je na programatorech jak toho vyuziji. Osobne pisu vzdycky private setter a public/internal getter pouze pokud vraci immutable tridu. Celkove potom Property zprehlednuji kod. 

Dalsi obrovskou vyhodou Properties je binding (WPF, WinForms). 

Ukazka kodu, pro predstavu s jakou "moderni" syntaxi prisli po 8 letech vyvojari Javy.

Java (2015):

public List<Article> getAllJavaArticles() {  
    return articles.stream()
        .filter(article -> article.getTags().contains("Java"))
        .collect(Collectors.toList());
    }

C# (2007):

public IEnumerable<article> GetAllJavaArticles() 
{ 
  return articles.Where(x => x.Tags.Contains("Java");
}
Nahlásit jako SPAM
IP: 37.188.233.–
Kit+15
Guru
30. 1. 2016   #7
-
0
-

#6 m4r10
Settery a gettery jsou v rozporu s OOP, dělají z objektového jazyka klasicky procedurální. Kdo chce programovat procedurálně, ten je používá.

OOP tyto blbosti nepotřebuje a nepotřebuje ani veřejné vlastnosti.

Binding je docela slušný antipattern, takže když nemám veřejné properties, nebudu nucen používat ani binding...

Nahlásit jako SPAM
IP: 194.228.68.–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
ondrej39+1
Věrný člen
30. 1. 2016   #8
-
0
-

#6 m4r10
Tento příspěvek už dává o něco větší smysl. Původní však, že Java nemá budoucnost, není zcela pravdivá.

Ano, Java má své mouchy a největší mouchou je právě JVM zajišťující přenositelnost systémů, ale také kvůli ní má dlouhý startup. Java je však založená i na dobrých věcech a jednou z nich je právě také JVM, díky které je Java hodně bezpečný jazyk, protože ti virtuální mašina odstiňuje vykonávání kódu od zbytku systému, což je jedním z důvodů, proč se Java tak dlouho používala v bankovnictví a dneska stále používá.

Jinakv tom tvém příkladě bys měl mít ve třídě Article metodu HasTag(string tagName), namísto toho, abys musel získávat kolekci a teprve na ní volat contains.

Nahlásit jako SPAM
IP: 46.39.172.–
Inject all the dependencies!
m4r100
Návštěvník
30. 1. 2016   #9
-
0
-

#7 Kit

Ano ciste settery a gettery jo, ale pokrocili vyvojari to nepouzivaji jako primy pristup k datum, ale jako implementaci business logiky. Ty bys napriklad (pro tridu reprezentujici poukaz) napsal metodu ChangeVoucherType(Type newType), ja pouze property VoucherType, ktera by v setteru mela stejnou logiku. Jedna se jenom o zjednoduseni a zprehledneni. 


Binding neni antipattern, ocividne si nikdy neprogramoval nejakou vetsi desktopovou aplikaci v .NET. 

Zkus si porovnat kod, ktery napises pomoci vzorce MVP bez bindingu a MVVM s bindingy. Hodne si zjednodusis a zprehlednis kod. Bindingy nejsou na urovni domenove logiky, je to pouze infrastrukturni vrstva, takze poruseni SOLID principu nevadi. 

Nahlásit jako SPAM
IP: 37.188.233.–
ondrej39+1
Věrný člen
30. 1. 2016   #10
-
+1
-
Zajímavé
Kit +

#4 Kit
Možná je dobře, že accessory nemají se SOLID principy absolutně nic společného.

Nahlásit jako SPAM
IP: 46.39.172.–
Inject all the dependencies!
Mufik
~ Anonymní uživatel
6 příspěvků
30. 1. 2016   #11
-
0
-

#6 m4r10
1. Použil bys na projekt ve firmě na projekt, který může stát stovky tisíc, Mono? Pokud vím, tak posledních X let nebylo pořádně ve vývoji. Já bych to teda nepoužil, jistota to není. Takže tak jako tak na Linuxu si .NEt v komerční praxi nespustíš.

2. Xamarin. Pokud vím, verze VS s Xamarinem stojí nějakých 20000,- na jednu stanici, + naposledy když jsem chtěl udělat app pro WP byl jsem přinucen nainstalovat si Windows 8. Těch dvacet tisíc není možná moc, ale opět, v komerční praxi - jak často potřebuješ updatovat na novou verzi VS? Co dva roky? To jsou prachy, které ti řeknou "pápá" a odletí do USA, místo totoho aby je dostal zaměstnanec či firma v ČR.

3. K tomu Visual Studiu si tedy připočti prachy na Windows na jednu stanici + prachy na Windows Server (a problémy s ním spojené oproti Linuxu, pokud jde o správování)

4. Dneska se stejně dělají převážně IS a tam Java EE nijak nezaostává. Na desktopové aplikace, nebo mobilní, je stejně nejlepší Qt a strčí obě platformy do kapsy.

5. Java má, narozdíl od C#, větší spektrum nasazení, vč. firem, které se zaobývají i hardwarem, mrkni někdy na nabídky práce. (třeba Škoda Transportation) Když někde dělají i s HW, takpoužívají nejspíš taky Linux, a proto samozřejmě použijí pro vysokoúrovňové věci Javu a ne C#. (jeden z důvodů proč jsem Javista)

6. Eclipse je narozdíl od VS multiplatformní a běží výborně i na Linuxu.

7. Microsoft. Nikdy bych si na počítač nedal takový OS, jako je Windows 10. Nejsem zatvrzelý linuxák, ale W10, to už je moc. Jsi li .NETista, řekni "ahoj, mám tě rád" svému novému bráškovi W10.

8. .NET je modernější a komfortnější jazyk než Java, ale není to zadarmo a to nejen po finanční stránce. Je otázka, na kolik se tyto rozdíly zcela smažou u seniorů javistů a .NETistů.

9. Podle Tiobe indexu .NET zrovna extra na vzestupu není, dost kolísá.

Nahlásit jako SPAM
IP: 90.179.206.–
Mufik
~ Anonymní uživatel
6 příspěvků
30. 1. 2016   #12
-
0
-

#11 Mufik
Jo pardon, ještě důležitá věc:

10. Popularita. Java je kvalitní a je zadarmo. S tím se táhne velká výhoda: knihovny. Nevím s jakými knihovnami jsi měl problémy ty. Asi ti nic neříká Maven.

Nahlásit jako SPAM
IP: 90.179.206.–
Kit+15
Guru
30. 1. 2016   #13
-
0
-

#9 m4r10
Ano ciste settery a gettery jo, ale pokrocili vyvojari to nepouzivaji jako primy pristup k datum, ale jako implementaci business logiky. Ty bys napriklad (pro tridu reprezentujici poukaz) napsal metodu ChangeVoucherType(Type newType), ja pouze property VoucherType, ktera by v setteru mela stejnou logiku.

Mýlíš se. Takovou metodu bych tam nedával - to by byl setter, ať už by se to jmenovalo jakkoli.

Místo toho vyrobím nový voucher správného typu, protože pokud je ten voucher jiného typu, musím ho udělat jako instanci jiné třídy - jiný typ voucheru bude mít i jiné atributy a jiné chování.

Jak bys řešil, kdyby ti zadavatel řekl, že máš do aplikace přidat nový typ voucheru?

Nahlásit jako SPAM
IP: 194.228.68.–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
m4r100
Návštěvník
30. 1. 2016   #14
-
0
-

#11 Mufik
1-4: Problem je, ze nerozlisujes male, stredni firmy vs stredne velke, obrovske, korporaty. V pripade tech prvnich mas pravdu, ze Java prostredi a linux bude ve vyhodne. U tech druhych je, ale naprosto bezne, ze vsichni vyvojari maji VS Ultimate s MSDN a nejaka 20K (s MSDN levnejsi) licence nikoho netrapi. 

To stejne co se tyce zakazniku, pro ty prvni spolecnosti bude klicove aby udrzeli cenu svych produktu nejnizsi, proto zvoli Javu a linux. Ale zakaznici tech druhych jsou naprosto odlisni, jedna se o zakazky v radech milionu, takze par tisic navic za licenci windows serveru nikoho nezajima. A hlavne zakaznik, ktery za software zaplati miliony a dalsich par let bude platit udrzbu, potrebuje nejakou jistotu, napr. support. Proc si myslis, ze vetsina obrovskych systemu bezi na Oracle DB nebo MSSQL, ktere stoji statisice a nepouziji napr. zdarma PostgreSQL?  

Co se tyce hardwaru, mas pravdu, ze tam bude Java rozsirenejsi, otazka jestli to neni jenom kvuli tomu, ze Java je tady delsi dobu a .NET nikdy poradne nebyl na tuto oblast cilen. 

Zase na druhou stranu, tam kde se pouziva napr. Windows mobile terminal, bankomaty, tam je .NET. 

Java je urcite aktualne jeste porad rozsirenejsi, jen by me zajimalo jestli se nejake nove systemy zacinaji psat v jave (o zadnych jsem neslysel), nebo kazdy radeji zvoli nejakou jinou platformu. Potom muze existovat stovky pracovnich prilezitosti pro javu, ale vsechny pro spravu starych systemu. Takova prace nikoho nebavi, lide rychleji odchazeji a nova pracovni nabidka je zase na svete. 

Nahlásit jako SPAM
IP: 37.188.233.–
ondrej39+1
Věrný člen
30. 1. 2016   #15
-
0
-

Na téma getterů, setterů, tohle je podle mě zcela validní kód a dobrá ukázka doménového modelu. Pokud se používají gettery na všechno, je to blbě. Nepoužívat je vůbec? Druhý extrém. Na získání dat z objektu není nic špatného.

class Pet
{
    public string Name { get; protected set; }

    public Pet(string name)
    {
        if (name == "") {
            throw new InvalidArgumentException("The name must not be empty.");
        }

        this.Name = name;
    }

    public void ChangeName(string newName)
    {
        if (newName == "") {
            throw new InvalidArgumentException("The name must not be empty.");
        }

        this.Name = newName;
    }
}
Nahlásit jako SPAM
IP: 46.39.172.–
Inject all the dependencies!
Kit+15
Guru
30. 1. 2016   #16
-
0
-

#15 ondrej39
Je na tom špatně to, že svému psovi jméno neměním. Na nové by totiž  neslyšel. Z tvého příkladu mi tedy zbude tohle: 

class Pet {
    public string Name;

    public Pet(string name) {
        if (name == "") {
            throw new InvalidArgumentException("The name must not be empty.");
        }
        this.Name = name;
    }
}

Pes, který má jméno, ale nereaguje na své okolí, je mrtvý. Je tedy jasné, že je to jen pahýl, kterému chybí chování. Změna jména však není chováním objektu, proto do něj nepatří.

Ještě k tomu dodám, že psa se neptám na jeho jméno. Proto ani getter nedává smysl.

Nahlásit jako SPAM
IP: 194.228.68.–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
ondrej39+1
Věrný člen
30. 1. 2016   #17
-
0
-

#16 Kit
Tak si třídu přejmenuj na Člověk, to je fuk. Řešíš nesmysl.

Nahlásit jako SPAM
IP: 46.39.172.–
Inject all the dependencies!
Kit+15
Guru
30. 1. 2016   #18
-
0
-

#17 ondrej39
Proč bych to měl přejmenovávat na Člověk, když je to Pes? Ani člověka se nebudu ptát na jméno, když budu mít jeho instanci. Budu se ho ptát na jméno při vytváření instance.

Tvůj příklad (a následně i můj) je syntakticky správně, ale chybí jim chování. Oba jsou tedy k ničemu.

Nahlásit jako SPAM
IP: 194.228.68.–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
m4r100
Návštěvník
30. 1. 2016   #19
-
0
-

#13 Kit
Mas pravdu, je to spatny priklad. Neni z toho vechno videt a lze se na to divat ze dvou pohledu. 

Jiny priklad, primo z praxe. Mame doklad, ktery muze byt ruzneho typu. Napr. prijmovy danovy doklad, vydajovy dd. faktura, pohledavka, p. pokladni d., atd.. Tyto typy jsou dane zakonem - nepredpoklada se, ze by se nejak razantne menily a data budou mit vsechny doklady stejna (proto pouziti polymorfismu je neopodstatnene a jenom by zkomplikovalo kod). Je tam, ale par drobnosti, pro ktere se tyto doklady lisi, napr. nekdy se meni dodavatel s odberatelem, nektere doklady maji zapornou hodnotu, jina validace, atd. Pokud uzivatel vystavuje doklad, vybira si jaky bude mit typ, muze ho menit. Nepouzil jsem metodu ChangeTyp(DokladTypeEnum newType), ale property Typ. Kde v setteru se vyhleda v kolekci TypChanger trid korektni instance pro novy typ dokladu a tato trida ma metody Apply(), Validate(), ktere se pouziji na dany doklad. 

Klienta, ktery tuto tridu pouziva uz nemusi zajimat jak to v pozadi funguje. Jenom vidi rozhrani, ve kterem je property Typ s pristupnym setterem, takze vi, ze ho muze pouzit. A nemusi nijak vytvaret nove instance dokladu (kdyz uz ma napr. propojene bindingy, bylo by to neoptimalni). 

Nahlásit jako SPAM
IP: 37.188.233.–
ondrej39+1
Věrný člen
30. 1. 2016   #20
-
0
-

#18 Kit
Validace jména je chování třídy. Je to její interní logika, kterou musíš při práci s ní respektovat. Ano, I tato třída chování má.

Jinak přeju hodně štěstí, když jméno člověka zapomeneš. ;-)

Nahlásit jako SPAM
IP: 46.39.172.–
Inject all the dependencies!
Kit+15
Guru
30. 1. 2016   #21
-
0
-

#19 m4r10
Polymorfismus není komplikací, ale výhodou, která se přesně na tvůj příklad hodí. Příjmový doklad má jiné chování než výdajový doklad nebo faktura a proto by to měly být instance různých tříd, které mohou mít společného rodiče Doklad.

Property Typ k ničemu nepotřebuji, proto je zbytečné ji tam dávat.

Nahlásit jako SPAM
IP: 194.228.68.–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
Kit+15
Guru
30. 1. 2016   #22
-
0
-

#20 ondrej39
Jméno člověka, tedy klíč, kterým ho oslovuji, je jménem objektu. Pokud zapomenu jméno objektu, GC mi ho sežere. Ovšem ty na tom nebudeš o nic lépe.

Pravidlo "Tell, don't ask" jasně říká, že se objektů nemáme na nic ptát, ale pouze jim přikazovat nebo, chceš-li, sdělovat změnu stavu okolí. Objekt by se sám měl rozhodnout, jak s danou informací naloží.

Nahlásit jako SPAM
IP: 194.228.68.–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
m4r100
Návštěvník
30. 1. 2016   #23
-
0
-

#21 Kit
Polymorfismus v tomto pripade je komplikaci, protoze doklad ma celkove obrovske mnozstvi dat a chovani mezi ruznymi typy dokladu je pouze minimalni, vetsina vlastnosti je spolecna. Predstav si, ze uzivatel ma vyplneny doklad (odberatel, dodavatel, polozky, datumy, hodnoty, atd...) a jenom chce zmenit typ dokladu (vybere z comboboxu jiny typ). Pokud bys v tomto miste chtel vytvaret novou instanci, musel bys znovu propojit bindingy, vsechny odkazy zaktualizovat, atd.. Chapu, ze tady bude rozdilnost mezi desktopovym vyvojem vs webovym. U toho druheho vytvareni nove instance nevadi, protoze se stav mezi pozadavky neudrzuje. 

Nahlásit jako SPAM
IP: 37.188.233.–
Kit+15
Guru
30. 1. 2016   #24
-
0
-

#23 m4r10
Ty dáváš do objektu víc než čtyři atributy? To není žádné obrovské množství.

Prostě vytvořím nový objekt jiné třídy a ty 2-4 atributy tam konstruktorem přesunu. To je hračka a získám tím nové chování nového objektu.

Nahlásit jako SPAM
IP: 194.228.68.–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
m4r100
Návštěvník
30. 1. 2016   #25
-
0
-

#22 Kit 

Zapomen na jmeno psa (ktere se menit nebude), ale treba neco realnejsiho: 

class Dog
{
    private DogCollar _collar;

    public string Name { get; private set; }
    public double CollarPerimeter { get { return _collar.Perimeter; } }

    public Dog(string name)
    {
        if (string.IsNullOrWhiteSpace(name)) {
            throw new ArgumentNullException("name");
        }

        Name = name;
        _collar = DogCollar.Nothing;
    }

    public void ChangeCollar(DogCollar collar)
    {
        if (collar == null) {
            throw new ArgumentNullException("collar");
        }
        if(collar == _collar)
            return;

        _collar = collar;
    }
}

O hodne prehlednejsi pouziti properties nez metod

Nahlásit jako SPAM
IP: 37.188.233.–
Kit+15
Guru
30. 1. 2016   #26
-
0
-

#25 m4r10
Stále nevidím žádné chování psa. Také nechápu, proč by si pes měl měnit obojek. I ten pes by na mne jistě čuměl, co to po něm vlastně chci. Sundat by si ho možná dokázal, ale nasadit druhý asi ne.

Ten příklad je opět k ničemu.

Nahlásit jako SPAM
IP: 194.228.68.–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
ondrej39+1
Věrný člen
31. 1. 2016   #27
-
+1
-
Zajímavé

#26 Kit
To mě fakt zajímá, jak změnu obojku vyřešíš ty. Ukaž.

Nahlásit jako SPAM
IP: 46.39.172.–
Inject all the dependencies!
Kit+15
Guru
31. 1. 2016   #28
-
0
-

#27 ondrej39
Změna vlastnosti objektu není jeho chováním.

Na změnu vlastnosti se používá klasický setter - jenže nevidím důvod, proč bych měl měnit vlastnosti nějakého objektu. Ještě by někoho mohlo napadnout k tomu napsat getter (ten už tam vlastně je) a predikát. To už by bylo moc na to, že ten objekt stále nic neumí, nemyslíš?

Za chování považuji např. u zmiňovaného dokladu zaúčtování nebo tisk. V tu chvíli je jedno, zda je to výdejka ze skladu nebo příjemka hotovosti. Zavolám metodu doklad.tisk() a doklad se vytiskne, ať je jakýkoli. K tomu žádný atribut Typ není potřebný.

Nahlásit jako SPAM
IP: 194.228.68.–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
ondrej39+1
Věrný člen
31. 1. 2016   #29
-
0
-

#28 Kit
Že má objekt nějaké chování je zcela v pořádku, to ti neberu. Že změna vlastností v surovém stavu není chováním objektu, proti tomu také nic nemám. Ale business logika limitující možnosti změny určitých vlastností při mutabilních operacích již chováním objektu je.

Nicméně odbíháš od tématu, nějaká funkce tisk mě vůbec nezajímá. Zajímá mě, jak tvým způsobem vyřešíš změnu obojku u psa, když píšeš, že on obojek měnit nemá. Zajímá mě, koho si myslíš, že je to v tvém případě zodpovědnost.

Představ si, že programuješ hru a v ní máš entitu pes, který může nosit obojek. Aktuálně má obojek kovový a chceš mu dát obojek gumový. Jak to uděláš?

Nahlásit jako SPAM
IP: 46.39.172.–
Inject all the dependencies!
Kit+15
Guru
31. 1. 2016   #30
-
0
-

#29 ondrej39
Zrovna tohle řeším inverzí: Obojek má atribut, kdo ho má na krku. Má k tomu metody nasadit() a sundat(). Podobně to může být s košíkem, batůžkem či oblečkem. Je tím zajištěno, že dva psi nemohou mít jeden obojek a že pes může mít víc obojků či dalších doplňků současně.

Dobře se s tím pracuje i při ukládání do databáze.

Nahlásit jako SPAM
IP: 194.228.68.–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
ondrej39+1
Věrný člen
31. 1. 2016   #31
-
0
-

#30 Kit
Počkej, takže chceš mi říct, že vztah, kdy pes MÁ obojek ti přijde divný, ale vztah, kdy obojek MÁ psa je úplně normální? A obojek má metody nasadit a sundat? Slovíčkaříš, že pes není schopen si nasadit obojek, protože na to postrádá dostatečnou mentální kapacitu, ale mít u obojku metodu nasadit, u věci, která mozek vůbec nemá, věci, která bez příčiny vnějšího činitele prostě blbě leží na takové místě, kde byla posledně odložena, ti přijde v pořádku?

Chlape, na tvých návrzích je ve své podstatě něco šíleně špatně.

Pro případ, že obojek může mít jen jednoho majitele, jednoho psa, by má návrh vypadal následovně:

class Collar
{
    protected int _diameter;
    public Colour _colour;
    protected Dog? _owner;

    public Collar(int diameter, Colour colour, Dog? owner = null)
    {
        if (diameter < 0) {
            // throw IAE, diameter may not be negative
        }

        this._diameter = diameter;	
        this._colour = colour;
        this._owner = owner; 
    }

    public void AssignOwner(Dog newOwner)
    {
        if (this.HasOwner() && this.BelongsTo(newOwner) == false) {
            // throw IAE, Collar may not have more than one owners
        }

        this._owner = newOwner;
    }

    public bool HasOwner()
    {
        return this._owner != null;
    }

    public bool BelongsTo(Dog dog)
    {
        return this._owner == dog;
    }

    public void RemoveCurrentOwner()
    {
        this._owner = null;
    }
}

class Dog
{
    public string Name { get; protected set; }
    protected List<Collar> _collars;

    public Dog(string name)
    {
        if (name == "") {
            // throw IAE, name must not be empty
        }

        this.Name = name;
        this._collars = new List<Collar>();
    }

    public void AddCollar(Collar collar)
    {
        collar.AssignOwner(this); // <- throws IAE
        this._collars.add(collar);
    }

    public bool HasCollar()
    {
        return this._collars.Count != 0;
    }
}
Nahlásit jako SPAM
IP: 46.39.172.–
Inject all the dependencies!
Kit+15
Guru
31. 1. 2016   #32
-
0
-

#31 ondrej39
Problémem tvého řešení je, že když do systému přidáš třeba náhubek, musíš přepsat třídu Pes. Přitom riskuješ, že zapomeneš upravit i třídu Medvěd. Vlastně zapomenout nemůžeš, protože kvůli tomu musíš změnit i jejich rozhraní :)

V mém případě jen přidám třídu Náhubek - na třídy Pes ani Medvěd přitom nemusím sáhnout a na jejich rozhraní už vůbec ne.

Nahlásit jako SPAM
IP: 194.228.68.–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
ondrej39+1
Věrný člen
31. 1. 2016   #33
-
+1
-
Zajímavé

#32 Kit
Ty vole, co sem pleteš nějaký medvědy? Bavíme se o psech, obojcích, způsobu řešení sundání obojku a o tom, jak může mít obojek metodu sundat. Neodpověděl jsi mi ani na jednu otázku, akorát si zase vymýšlíš jiný věci, které nikoho nezajímají a vůbec nejsou předmětem diskuze. Až budeš znát odpovědi na otázky, které jsem ti položil, sepiš je do odpovědi a bumpni mě. Díky.

Nahlásit jako SPAM
IP: 46.39.172.–
Inject all the dependencies!
Kit+15
Guru
31. 1. 2016   #34
-
0
-

#33 ondrej39
Z mého pohledu jsou tvé otázky typu: "Jak bys zatloukal vruty pilkou?" Proto je pro mne obtížné na to odpovědět. Když už odpovím, označíš to za vyhýbání odpovědi. Takže nic.

Všechno, co jsi ukázal, jsou gettery a settery, protože manipulují s atributy objektu - nikoli s objektem. Možná se tak programuje v C++, ale do OOP tohle nepatří.

Klidně si dál v Javě či C# programuj procedurálně, mně to vadit nebude.

Nahlásit jako SPAM
IP: 194.228.68.–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
ondrej39+1
Věrný člen
31. 1. 2016   #35
-
0
-

#34 Kit
Nezodpovězené otázky nebo nevyřešené problémy:

  1. To mě fakt zajímá, jak změnu obojku vyřešíš ty. Ukaž.

    Není ukázaný reálný kód, akorát stížnost, že změna vlastností objektů není jejich chování a zmíněná nějaká metoda tisk, tudíž odkazování se na problémy, které v původním případě nebyly předmětem diskuze.

    Chybí: ukázka kódu.
  2. Počkej, takže chceš mi říct, že vztah, kdy pes MÁ obojek ti přijde divný, ale vztah, kdy obojek MÁ psa je úplně normální?

    Kompletně ignorovaná otázka, odpověď není.
  3. A obojek má metody nasadit a sundat? Slovíčkaříš, že pes není schopen si nasadit obojek, protože na to postrádá dostatečnou mentální kapacitu, ale mít u obojku metodu nasadit, u věci, která mozek vůbec nemá, věci, která bez příčiny vnějšího činitele prostě blbě leží na takové místě, kde byla posledně odložena, ti přijde v pořádku?

    Viz Částečně zodpovězené otázky nebo vyřešení problémy, 1., kvůli částečné vazbě. Jinak otázka rovněž zcela ignorována a odpověď na ni neexistuje.

Částečně zodpovězené otázky nebo částečně vyřešené problémy:

  1. Zajímá mě, jak tvým způsobem vyřešíš změnu obojku u psa, když píšeš, že on obojek měnit nemá. Zajímá mě, koho si myslíš, že je to v tvém případě zodpovědnost.

    Z původní verze, kdy za změnu obojku byla zodpovědná třída Pes, verze, která se ti nelíbila, protože dle tvého názoru pes postrádá mentální kapacitu na to, aby si mohl obojek vyměnit, jsi delegoval výměnu obojku přímo do třídy obojek, tedy do předmětu, který sám o sobě dělá ještě méně než ten hloupý pes. Tzn. obojek se sám rozhodně nevymění.

    Chybí: zdůvodnění, proč ti delegace do třídy obojek, který nic neumí, přijde v pořádku, zatímco výměna obojku ve třídě pes nikoliv.
     

Víceméně jsi neodpověděl na nic, akorát si pořád vymýšlíš další a další problémy, které jsou nerelevantní. Tady máš sepsané otázky pohromadě, teď už bys měl vědět, na co chci odpovědi znát, ať to nemusíš hledat.

EDIT: Pokud bude předmětem tvé případné odpovědi na tento příspěvek něco jiného, než zodpovězení zmíněných otázek, ani odepisovat nemusíš.

Nahlásit jako SPAM
IP: 79.141.243.–
Inject all the dependencies!
Kit+15
Guru
31. 1. 2016   #36
-
+2
-
Zajímavé

#35 ondrej39

  1. Změnu obojku buď neřeším vůbec, anebo ho z donucení udělám setterem. Pokud však mám možnost, tak změním návrh aplikace tak, abych ten setter nepotřeboval, viz níže.
  2. Pes může a nemusí mít obojek, může jich mít několik. Pokud dám psovi obojek, musím toho psa naučit, jak s ním zacházet (settery, gettery). Pokud totéž udělám s obojkem, situace se zjednoduší, protože jeden obojek nemůže být současně na více zvířatech. Prostřednictvím obojku mohu případně psovi předávat povely. Ber to jako jiný pohled na problém, který se někdy může hodit, jindy třeba zase ne.
  3. To slovíčkaření mělo ten smysl, že tentýž obojek mohu nasadit třeba medvědovi, ale ne psovi a medvědovi současně. Mohu tedy metodě Obojek.nasadit() dát jako parametr psa nebo medvěda, resp. jakékoli ZvířeSchopnéNositObojek, což je rozhraní. Pokud obojek přijme nějakou událost, může na jejím základě předat informaci zvířeti, které ho má na krku.

Tou "mentální kapacitou psa" jsem měl na mysli právě tu zodpovědnost, aby pes nebyl zodpovědný za každou blbost, kterou na něj navlečeš (obojek, náhubek, obleček,...). Samozřejmě když provedeš náhubek->nasadit(pes), je nutné, aby se pes dozvěděl, že má náhubek a že tedy není schopen aportovat. Náhubek mu pošle patřičnou notifikaci. Když pak uděláš pes.aport(klacík), musí vyhodit výjimku. Obojek psa nijak neomezuje a proto ta notifikace není nutná.

Věř mi, že tuto konstrukci mám nasazenu v nejedné ostré aplikaci, které bezvadně fungují a také se skvěle udržují, protože třídy vycházejí velmi jednoduché a potřebují jen minimum metod. Jsou i rychlejší.

Nahlásit jako SPAM
IP: 194.228.68.–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
lukas.balaz0
Super člen
1. 2. 2016   #37
-
0
-

Zaujímavá diskuzia :) ... Doteraz mi nikdy nepadlo riešiť veci tak, ako píše Kit, takže diki, naučil som sa nový spôsob, ako sa dá na to pozerať :). Ale aj tak asi ostanem pri mojom starom spôosobe, to je niečo podobné, ako píšu ostatní. S OOP pracujem relatívne krátko, len niekoľko mesiacov (a aj to som zatiaľ pracoval takmer výradne s ModelViewController vecami), ale aj tak som sa už o tom dosť načítal. Zaujímavé, že s tým prístupom, ktorý popisuje Kit, som sa ešte nestretol, aj keď vyzerá dosť logicky. Možno preto, že na prvý pohľad je trochu neintuitívny ...

Nahlásit jako SPAM
IP: 80.242.41.–
Kit+15
Guru
1. 2. 2016   #38
-
0
-

#37 lukas.balaz
Je za tím několik měsíců neustálého přemýšlení a zkoušení, jak zjednodušit Model v architektuře MVC. Pořád jsem laboroval nad tím, jak Model zjednodušit injektováním závislostí. Výsledkem je modulární Model, který má konstruktor a jen 5 metod. Gettery, settery ani veřejné atributy nemá. Přesto poskytuje veškerá data, která po něm chci. Pro jeho moduly (domény) platí totéž.

Jenom mám tak trochu obavu, že jsem "objevil" DDD, tedy něco, co tady je už hodně dlouho. Nevadí. Funguje to, je to bezvadně udržovatelné a používám to už systematicky i v drobných projektech, které mají víc než jednu doménu.

Nahlásit jako SPAM
IP: 194.228.68.–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
lukas.balaz0
Super člen
1. 2. 2016   #39
-
0
-

#38 Kit
Mohol by si mi prosím ťa dať nejaký menší kús reálneho kódu, aby som presnejšie pochopil, ako to myslíš ?

Lebo teda ako poznám MVC (alebo skôr ako ja používam MVC), tak model má data; povie controlleru (cez delegáciu), keď sa mu data zmenia; controller zistí, o aký sa jedná view; spustí na ňom metódu reloadData(); tá sa spýta (cez svojho dataSource, čo je podobné ako delegate) controllera na to, čo potrebuje; controller tam vráti data z modela; view data spracuje a podľa toho sa zmení. Viem, že je to hnusný postup, ale páči sa mi na ňom, že všetko je poodelované; keď potrebujem z nejkého dôvoodu reloadnúť view, tak proste na ňom spustím reloadData() a on sám sa postará o ostatné. Týmto postupom som chcel hlavne docieliť, aby som nemusel priamo meniť atribúty view v controlleri, a takto keď to má na starosti view samotný, dosť sa s tým dobre pracuje.

Okrem toho, dosť podobným spôsobom to má riešené aj UIKit (to je framework na programovanie na IOS), tam je napr. UICollectionView (teda view, ktorý vie mať v sebe kolekciu viewov) a on sa takýmto spôsobom pýta jeho dataSource ako majú vyzerať jeho views sôsobom: "vytvor a vrát mi view na indexe 3". Tam sa to asi ani nedá riešiť inak, ako sa priamo spýtať modelu (cez jeho gettery).

Nahlásit jako SPAM
IP: 80.242.41.–
ondrej39+1
Věrný člen
1. 2. 2016   #40
-
0
-

#36 Kit
Díky za odpověď. Chápu to tedy správně, že tvůj návrh by vypadal například takhle (komentáře a konvence názvu proměnných stranou, podtržítka prostě používám, vím, že ty je rád nemáš)?

interface ZvireNosiciObojek
{
    public function priraditObojek(Obojek $obojek);
    public function maObojek();
}

interface AportovatelnaVec
{
    public function zvireJiUnese(AportujiciZvire $zvire);
}

class Klacik implements AportovatelnaVec
{
    protected $_hmotnost;

    public function __construct($hmotnostVeci)
    {
        $this->_hmotnost = $hmotnostVeci;
    }

    public function zvireJiUnese(AportujiciZvire $zvire)
    {
        return $zvire->zvireUneseVecDaneHmotnosti($this->_hmotnost);
    }
}

interface AportujiciZvire extends ZvireNosiciObojek
{
    public function aportuj(AportovatelnaVec $vecKAportovani);
    public function zvireUneseVecDaneHmotnosti($hmotnost);
}

class Pes implements AportujiciZvire
{
    /** @var Obojek[] */
    protected $_obojky;

    public function priraditObojek(Obojek $obojek)
    {
        $obojek->nastavitMajitele($this);
        $this->_obojky[] = $obojek;
    }

    public function maObojek()
    {
        return (count($this->_obojky) > 0);
    }

    public function aportuj(AportovatelnaVec $vecKAportovani)
    {
        if ($vecKAportovani->zvireJiUnese($this) == false)
        {
            throw new InvalidArgumentException('Věc je moc těžká. Zvíře ji neunese.');
        }
    }

    public function zvireUneseVecDaneHmotnosti($hmotnost)
    {
        return $hmotnost <= 5; // Třeba, že unese max 5 KG
    }
}

class Obojek
{
    /** @var int */
    protected $_prumer;

    /** @var string */
    protected $_barva;

    /** @var ZvireNosiciObojek */
    protected $_majitel;

    public function __construct($prumer, $barva)
    {
        $this->_prumer = $prumer;
        $this->_barva = $barva;
        $this->_majitel = null;
    }

    public function nastavitMajitele(ZvireNosiciObojek $novyMajitel)
    {
        if ($this->maMajitele() && $this->_majitel != $novyMajitel)
        {
            throw new InvalidArgumentException('Obojek může mít pouze jednoho majitele.');
        }

        $this->_majitel = $novyMajitel;
        $novyMajitel->priraditObojek($this);
    }

    public function maMajitele()
    {
        return $this->_majitel != null;
    }

    public function nemaMajitele()
    {
        return !$this->maMajitele();
    }
}
Nahlásit jako SPAM
IP: 78.156.159.–
Inject all the dependencies!
Kit+15
Guru
1. 2. 2016   #41
-
0
-

#40 ondrej39
Tak takhle určitě ne. Proč bych měl psát metody maObojek() nebo třeba maMajitele(), když je k ničemu nepotřebuji? Zkus vyhodit všechny metody, které vrací hodnotu nějakého atributu. Pak vyhoď metody, které nastavují nějaký atribut. Na tom se pak dá začít stavět.

Nahlásit jako SPAM
IP: 194.228.68.–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
ondrej39+1
Věrný člen
1. 2. 2016   #42
-
0
-

#41 Kit
Dobře, v tom případě buď, prosím, tak laskav, a zpachtli ty sám příklad, jak bys daný problém řešil. Protože očividně vůbec nechápu, jak to myslíš.

Nahlásit jako SPAM
IP: 78.156.159.–
Inject all the dependencies!
Kit+15
Guru
1. 2. 2016   #43
-
0
-

#39 lukas.balaz
Nevím, jestli by to k něčemu bylo, protože zatím to mám pouze v PHP. Kromě toho nemám vůbec žádnou vazbu mezi controllerem a view - tyto bloky o sobě nevědí. Model ani do view neposílá žádné anotace - pouze data, pokud o ně view požádá. Obráceně controller posílá do modelu rozkazy, ale zpět nedostává žádná data.

Podle popisu používáš spíš architekturu MVP, kde controller (presenter) je tím prostředníkem, který všechno řídí. To se hodí na desktop, ale na server už méně.

Ve svém MVC mám mnoho controllerů a mnoho view. Také model se skládá z většího množství relativně samostatných domén. Vždycky mu injektuji jen tu doménu, se kterou má aktuálně pracovat. Jakmile je úkol hotov, konfiguraci zapomene. Pamatuje si pouze odkazy na vnitřní zdroje dat (databázi).

Jak vidíš, architektura je zcela odlišná. Je tam ještě jedna drobná odchylka u ajaxového volání, kdy router na vstupu vyrobí a zavolá nejprve controller (aby změnil stav) a ze stejného objektu zavolá i view (je to jen jedna metoda). Tohle ještě nemám zcela dořešeno, protože view i controller v jedné třídě je tak trochu v rozporu s architekturou MVC, ale funguje to a nic lepšího mě dosud nenapadlo.

Nahlásit jako SPAM
IP: 194.228.68.–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
Zjistit počet nových příspěvků

Přidej příspěvek

Toto téma je starší jak čtvrt roku – přidej svůj příspěvek jen tehdy, máš-li k tématu opravdu co říct!

Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku

×Vložení zdrojáku

×Vložení obrázku

Vložit URL obrázku Vybrat obrázek na disku
Vlož URL adresu obrázku:
Klikni a vyber obrázek z počítače:

×Vložení videa

Aktuálně jsou podporována videa ze serverů YouTube, Vimeo a Dailymotion.
×
 
Podporujeme Gravatara.
Zadej URL adresu Avatara (40 x 40 px) nebo emailovou adresu pro použití Gravatara.
Email nikam neukládáme, po získání Gravatara je zahozen.
-
Pravidla pro psaní příspěvků, používej diakritiku. ENTER pro nový odstavec, SHIFT + ENTER pro nový řádek.
Sledovat nové příspěvky (pouze pro přihlášené)
Sleduj vlákno a v případě přidání nového příspěvku o tom budeš vědět mezi prvními.
Reaguješ na příspěvek:

Uživatelé prohlížející si toto vlákno

Uživatelé on-line: 0 registrovaných, 1 host

Podobná vlákna

Jazykové dilema — založil JiriVavru

O Jave — založil echo112

Hudba v Jave — založil ospaly.stanislav

Notepad v javě — založil Anonymní uživatel

Moderátoři diskuze

 

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032024 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý