OOP jazyk - problém klasického stříhu

Honza

Re:OOP jazyk - problém klasického stříhu
« Odpověď #30 kdy: 06. 06. 2018, 21:50:42 »
Důležité je, že se jedná o související funkce, na tom se shodneme. Ale já mám namysli konkrétní implementaci algoritmu, která provede uložení toho objektu User, a ta patří v každém případě jinam! Teprve potom totiž můžu ukládat do databáze, do souboru, nebo třeba do HTML. Právě tento princip např. Active Record porušuje.

V reálu ale ten algoritmus obvykle není implementovány v třídě User, ale je do třídy User zděděný z předka anebo doplněný weavingem (např. v bytekódu). Což už není tak špatné řešení. Můžu mít taky traity a těmi entitu User uschopnit k tomu, aby se uměl uložit do souboru, do databáze, poslat mailem apod. a ani zde nebude ta implementace pomíchaná s entitou. Případně můžu použít vzor dekorátor. Který postup bude dávat smysl bude opět záležet na zbytku aplikace. Zda to je nebo není pravověrné OOP nedokážu říct. IMHO nejhorší z těch variant  bývá dědění, protože je příliš rigidní.
Já bych měl k tomu generování bytekódu trochu výhrady, ale budiž. To dědění bych škrtnul rovnou, ale na té implementaci mimo třídu User se asi shodneme.


ded.kenedy

Re:OOP jazyk - problém klasického stříhu
« Odpověď #31 kdy: 06. 06. 2018, 21:54:41 »
Cely problem, ktery tu byl nastinen, nejde posuzovat podle jednotlivosti (jak se tu nekteri snazi), ale musi se posuzovat jako celek v konkretnim kontextu.

Citace
Jediné zmatení je, zda se bavíme o tom, jestli ten objekt vůbec smí mít metodu save(), zda to samo o sobě porušuje nějaký princip, nebo zda má tu příslušnou operaci také sám provést.

Jestli ma byt metoda save nebo ne soucasti objektu, je ve velke mire dano, jestli tim bude narusen SRP (single responsibility principle), tj. zda bude objekt mit jednu konkretni odpovednost, nebo ne.

Kit

Re:OOP jazyk - problém klasického stříhu
« Odpověď #32 kdy: 06. 06. 2018, 21:59:45 »
To přece neříkám přímo emailu nebo databázi, ale nějakým proxy, které tento úkon udělají.
Pokud má objekt User službu „ulož se“, neříkám to žádné proxy, ale přímo tomu objektu User. A ten objekt musí vědět, že existuje nějaká proxy, která to uložení provede. Proč? Když budu chtít objekt User poslat e-mailem, budu muset jeho rozhraní rozšířit o „pošli se e-mailem“, což zase bude jen převolání nějaké proxy. To samé validace, tisk…

Však už jsem to psal:
Kód: [Vybrat]
User.send(database);
User.send(email);
...

Ve všech případech to říkám nějaké proxy: database, email, validace, tisk...

Re:OOP jazyk - problém klasického stříhu
« Odpověď #33 kdy: 06. 06. 2018, 22:05:43 »
Ve všech případech to říkám nějaké proxy: database, email, validace, tisk...
Ne, ve všech případech to říkáte objektu User (posíláte mu zprávu „send“). A těžko pokryjete vše, co lze s objektem User dělat, jednou službou send s jedním rozhraním.

Re:OOP jazyk - problém klasického stříhu
« Odpověď #34 kdy: 06. 06. 2018, 22:12:43 »
Jestli ma byt metoda save nebo ne soucasti objektu, je ve velke mire dano, jestli tim bude narusen SRP (single responsibility principle), tj. zda bude objekt mit jednu konkretni odpovednost, nebo ne.

Ano a to je u každé aplikace různé. Navíc se s rozvojem aplikace ta hranice posouvá - co do zodpovědnosti patří a co už ne. Takže se programátor snaží predikovat, na jak dlouho dopředu se vyplatí myslet a hledá optimum mezi složitostí a univerzálností.


Kit

Re:OOP jazyk - problém klasického stříhu
« Odpověď #35 kdy: 06. 06. 2018, 22:14:40 »
Ve všech případech to říkám nějaké proxy: database, email, validace, tisk...
Ne, ve všech případech to říkáte objektu User (posíláte mu zprávu „send“). A těžko pokryjete vše, co lze s objektem User dělat, jednou službou send s jedním rozhraním.

Pokud budu potřebovat, tak to rozhraní mohu přetížit. V objektu User je jednořádková metoda send(), která zavolá tu proxy a předá jí data. Na tom není nic složitého, prostě DI.

Re:OOP jazyk - problém klasického stříhu
« Odpověď #36 kdy: 06. 06. 2018, 22:18:07 »
Ve všech případech to říkám nějaké proxy: database, email, validace, tisk...
Ne, ve všech případech to říkáte objektu User (posíláte mu zprávu „send“). A těžko pokryjete vše, co lze s objektem User dělat, jednou službou send s jedním rozhraním.

Což může být právě vodítko, že kompetence „send“ má jít do jedné třídy a kompetence „save“ do druhé. Musím přemýšlet, zda se nedostávám do problémů, pokud musím psát „sendEmail“ abych to odlišil od „sendPersonalMessage“.

Re:OOP jazyk - problém klasického stříhu
« Odpověď #37 kdy: 06. 06. 2018, 22:23:51 »
Důležité je, že se jedná o související funkce, na tom se shodneme. Ale já mám namysli konkrétní implementaci algoritmu, která provede uložení toho objektu User, a ta patří v každém případě jinam! Teprve potom totiž můžu ukládat do databáze, do souboru, nebo třeba do HTML. Právě tento princip např. Active Record porušuje.

V reálu ale ten algoritmus obvykle není implementovány v třídě User, ale je do třídy User zděděný z předka anebo doplněný weavingem (např. v bytekódu). Což už není tak špatné řešení. Můžu mít taky traity a těmi entitu User uschopnit k tomu, aby se uměl uložit do souboru, do databáze, poslat mailem apod. a ani zde nebude ta implementace pomíchaná s entitou. Případně můžu použít vzor dekorátor. Který postup bude dávat smysl bude opět záležet na zbytku aplikace. Zda to je nebo není pravověrné OOP nedokážu říct. IMHO nejhorší z těch variant  bývá dědění, protože je příliš rigidní.
Já bych měl k tomu generování bytekódu trochu výhrady, ale budiž. To dědění bych škrtnul rovnou, ale na té implementaci mimo třídu User se asi shodneme.

Takže když shrneme původní dotaz, celá otázka se redukuje na to, zda implementaci do entity vůbec pustíme a odkud. Některé ORM frameworky umí více způsobů a lze si mezi vybrat. Samotná metoda save u entity není v rozporu s OOP, což ale neznamená, že je vše předem vyřešeno. Tak jako tak bude potřeba vyřešit řadu dilemat :-)

Re:OOP jazyk - problém klasického stříhu
« Odpověď #38 kdy: 06. 06. 2018, 22:34:59 »
Ve všech případech to říkám nějaké proxy: database, email, validace, tisk...
Ne, ve všech případech to říkáte objektu User (posíláte mu zprávu „send“). A těžko pokryjete vše, co lze s objektem User dělat, jednou službou send s jedním rozhraním.

Pokud budu potřebovat, tak to rozhraní mohu přetížit. V objektu User je jednořádková metoda send(), která zavolá tu proxy a předá jí data. Na tom není nic složitého, prostě DI.

Co kdyz budu mit v aplikaci dalsi tabulky? Customers, Officers, Managers...
A taky jim chci umet poslat email, ulozit do databaze, vypsat do logu...
Bude mit kazda svou tridu? Kazda metodu save, send, toString?
Budou implementovat stejne rozhrani?
Budou ty proxy umet pracovat se vsemi takovymi tridami? Nebo bude pro kazdy typ jina proxy?



Kit

Re:OOP jazyk - problém klasického stříhu
« Odpověď #39 kdy: 06. 06. 2018, 22:35:59 »
Ve všech případech to říkám nějaké proxy: database, email, validace, tisk...
Ne, ve všech případech to říkáte objektu User (posíláte mu zprávu „send“). A těžko pokryjete vše, co lze s objektem User dělat, jednou službou send s jedním rozhraním.

Což může být právě vodítko, že kompetence „send“ má jít do jedné třídy a kompetence „save“ do druhé. Musím přemýšlet, zda se nedostávám do problémů, pokud musím psát „sendEmail“ abych to odlišil od „sendPersonalMessage“.

Ne, ve všech případech použiji metodu send(). V parametru uvedu, komu to má poslat.

Kit

Re:OOP jazyk - problém klasického stříhu
« Odpověď #40 kdy: 06. 06. 2018, 22:42:12 »
Co kdyz budu mit v aplikaci dalsi tabulky? Customers, Officers, Managers...
A taky jim chci umet poslat email, ulozit do databaze, vypsat do logu...
Bude mit kazda svou tridu? Kazda metodu save, send, toString?
Budou implementovat stejne rozhrani?
Budou ty proxy umet pracovat se vsemi takovymi tridami? Nebo bude pro kazdy typ jina proxy?

Ano, ano, ano.

Nejsme však omezeni na jednu metodu send(). Ve třídách mívám 3-5 metod s poměrně unifikovanými názvy.

BoneFlute

  • *****
  • 2 062
    • Zobrazit profil
Re:OOP jazyk - problém klasického stříhu
« Odpověď #41 kdy: 06. 06. 2018, 23:13:14 »
Ty objekty vždy něco reprezentují. Například Máslo reprezentuje entitu másla. Má nějaké vlastnosti jako velikost, váhu, výrobce...

Pak mám samozřejmě nějaké úložiště Lednice, Košík. To má také nějaké vlastnosti, třeba kapacitu.

Potud všechno jako podle knižního ideálu reprezentuje objekty reálného světa.

Jenže pak máte věci, které jsou taky objekty. A to jsou procesy. Například proces Nákup, DodáníZboží, Naskladnění, Inventura. To jsou také naprosto plnohodnoté objekty. V nich figurují víše uvedené objekty, ale také je zde hlavně uložena logika toho procesu (různé ACL, posílání výkazů, strhávání plateb, etc). A právě tady, protože to korensponduje s tím názvem.

Samozřejmě bychom tu logiku mohli hodit do vhodně pojmenovaných metod, a ty přilepit k více méně adekvátnímu objektu (Máslo se umí Nakoupit, nebo spíše Lednice umí Nakoupit?). Nemyslím si, že by to pak bylo objektovější - spíše naopak; třeba už jen z toho důvodu, že nemůžem nahrazovat procesy jak se nám líbí: Pepa umí Nakoupit, DodatZboží, Naskladňovat...

« Poslední změna: 06. 06. 2018, 23:16:29 od BoneFlute »

Youda

Re:OOP jazyk - problém klasického stříhu
« Odpověď #42 kdy: 06. 06. 2018, 23:14:05 »
Vidim, ze tu dneska proklate bouri mozky, clovek se stale uci, dnes jsem se o OOP a Springu zase dozvedel spoustu noveho, napr ze boura OOP.

Ja bych cely problem resili proste.
A to prachobycejnym Springem MVC s IoC.

A tak vyrobim Spring komponentu @Controller, ktera obsahuje model sveta, vcetne registru Useru a definuje, jake akce se s Usery daji provadet pomoci @Service komponenty nad @Repository. User je prachsprosty POJO payload v tomto procesu (pripadne Hibernate entity, coz je to same s anotacema pro ORM), obdoba ceckoveho structu a neco jako User.save() jest naprosta picovina.
SpringMVC vlastne rika, ze spravny pristup je Lopato.priloz(Uhli), kdezto pristup definovany v tomto boureni mozku je Uhli.prilozSePomoci(Lopata) - tedy skolacke nepochopeni OOP.
Instancim User ani Uhli se zadne zpravy neposilaji, ony jsou temi zpravami.

A jestli chci podporovat save(User) a sendMail(User) - pres @Autowired si do @Controlleru naseru @Services cely kybl, treba pro posilani SNMP trapu...

Re:OOP jazyk - problém klasického stříhu
« Odpověď #43 kdy: 06. 06. 2018, 23:14:35 »
Co kdyz budu mit v aplikaci dalsi tabulky? Customers, Officers, Managers...
A taky jim chci umet poslat email, ulozit do databaze, vypsat do logu...
Bude mit kazda svou tridu? Kazda metodu save, send, toString?
Budou implementovat stejne rozhrani?
Budou ty proxy umet pracovat se vsemi takovymi tridami? Nebo bude pro kazdy typ jina proxy?

Ano, ano, ano.

Nejsme však omezeni na jednu metodu send(). Ve třídách mívám 3-5 metod s poměrně unifikovanými názvy.

Jo je to validní řešení akorát se asi nehodí všude. Co když nemám k té entitě zdroják? Pak asi budu postupovat opačně, budu mít service která přijme jako parametr tu entitu nebo budu psát  nějaký adaptér. Ve výsledku se mi ten tvůj přístup pak nemusí hodit.

Youda

Re:OOP jazyk - problém klasického stříhu
« Odpověď #44 kdy: 06. 06. 2018, 23:29:41 »
Co kdyz budu mit v aplikaci dalsi tabulky? Customers, Officers, Managers...
A taky jim chci umet poslat email, ulozit do databaze, vypsat do logu...
Bude mit kazda svou tridu? Kazda metodu save, send, toString?
Budou implementovat stejne rozhrani?
Budou ty proxy umet pracovat se vsemi takovymi tridami? Nebo bude pro kazdy typ jina proxy?

Ano, ano, ano.

Nejsme však omezeni na jednu metodu send(). Ve třídách mívám 3-5 metod s poměrně unifikovanými názvy.

Pred casem jsi psal, ze kazdy takovy datovy bean delas immutable inicializovany konstruktorem, bez getteru a setteru.
K cemu je dobra u immutable beanu metoda save? Ze se to zkonstruuje, pak se to jednou ulozi pres save(), pri zmene se to cele zahodi a sestavi lautr znova?
Zajimave.