Jste zastánci OOP programování?

ondra.novacisko.cz

Re: Jste zastánci OOP programování?
« Odpověď #90 kdy: 09. 12. 2010, 00:03:56 »

Citace
Hlavní smyslem OOP je re-usability, a tímto přístupem právě tenhle smysl jaksi narušujete.
??? Jaksi nechápu čím narušuji reusabilitu??? Já tvrdím, že se objekty mají navrhovat korektně, i když třeba některé jejich vlastnosti (např. možnost mít více psů) se v dané chvíli nevyužijí. A to rozhodně re-usabilitu zvyšuje a ne naopak.

To Vy tady hájíte myslivce s jedním psem, který v následném vývoji dělá problémy s re-usabilitou, ne já.
[/quote]
No tím že změníte rozhraní musíte reimplementovat všechny objekty, nemůžete tedy znovu-použít to co už máte napsáno ve smyslu objektového. Já vím, že vy namítnete, že ta reimplementace se může omezit jen na vhodnou variantu find-replace v textovem editoru, ale tak jednoduché to vždycky není. Spoléhat se při programování na schopnosti editoru je vyloženě špatné.

Proč používáme konstanty, když mohu v celém programu jednu konstantu za jinou nahradit pomocí editoru?


D.A. Tiger

  • ****
  • 486
  • Tygr, který žere tučňáka ;-)
    • Zobrazit profil
    • E-mail
Re: Jste zastánci OOP programování?
« Odpověď #91 kdy: 09. 12. 2010, 00:44:46 »
Ondra.novačisko.cz

já si nejdřív dovolím trochu hnidopišství :
Kód: [Vybrat]
class IMyslivec2: public IMyslivec {
  int akt_pes;
public:
   void selectPes( int id = 0 ) { if( ( get_psy( ).size( ) > id ) && (0 >= id ) ) { act_pes = id }; }
   virtual PsiKontejner &getPsy() = 0;
   virtual IPes *getPes() {return getPsy().empty()?0:&getPsy()[ act_pes ];}
};

... nikde v zadání není psáno ni o tom, že myslivec co má víc psů bude používat jen jednoho - pak by taková úprava byla IMHO trochu o zbytečná (ještě tam chybí informace o tom, kolik těch psů vlastně má) :-)

Vaše řešení třídy myslivec není přímo prasácké, určitě je funkční a v mnoha situacích určitě lepší než přepisovat celou knihovnu, ale mě to přijde trochu ... násilné.

Mě kdysi učily, že když mám skříň (myslivce) mohu do ni dát jeden šálek (může mít psa). Pokud ovšem nikde není napsáno, že do této skříně mohu dát jen a pouze jeden šálek (tedy myslivec smí mít pouze jen jednoho psa) musí jit do skříně dát více šálku (každý myslivec může mít psů více). A hlavně nám bylo zdůrazněno, že musíme počítat s tím, že dřív či později bude někdo chtít dát do té skříně šálku hned dva, deset, ... (tedy, myslivec půjde na hon s celou smečkou). Nemluvě o tom, že do skříně mohu dát také talíře, sváteční košile, nebo sbírku angličáků (tedy myslivec může mít kokršpaněly, jezevčíky, ... nebo třeba pudly). Popřípadě od všeho něco. Vyhoví třída myslivec těmto požadavkům? Takže otázku "Koho jsem si to sakra do firmy nasadil?", bych si položil při pohledu na nedodělanou bázovou třídu IMyslivec.

a co to skusit už od začátku třeba takto nějak "

Kód: [Vybrat]
class z_JedenCokl {
  ...
  IPes* get_Pes( );          /// Pes ;-)
};

class z_PsiSmecka {
  ...
  int no( )  { ... }                        /// Pocet ratafaku
  void AktualniPes( int id ) {...}     /// Vyberu si psa ze smecky
  IPes* get_Pes( ) { ... }             /// A budu s nim neco vyvadet
}


template <typename T> class IMyslivec : public T {
 
 /// Metody rozhrani myslivec
 JdiNaLov( IHonidba *h );
};


Tak to bychom měly :) Myslivce máme jasně definovaného, a nijak nezasahujem do jeho deklarace a přesto mohu určit s jakymi a kolikati psy bude konkretni myslivec fungovat :

Kód: [Vybrat]
    class z_NoPes { };
    ...

  IMyslivec<zasada_JedenCokl> *HajnyA = new IMyslivec<z_JedenCokl>;
  IMyslivec<z_PsiSmecka> *HajnyB = new IMyslivec<z_PsiSmecka>;
  IMyslivec<z_NoPes> *HajnyC = new IMyslivec<z_NoPes>;
     
  ...
  IHonidba *hon;

 

Tomuto způsobu se říká zásady. A jde v podstatě o to, že vaše šablona myslivec určuje základní rozhraní a chování (řekl bych jakýsi rámec) objektu. Zásady jsou potom malé moduly, vyhovující přesně vaším požadavkům, kterými doplníte možnosti původního objektu. Nejde tu to jak jsou jednotlivé třídy implementovány, ale o jejich rozhraní (proto jsem se ze své vrozené lenosti neobtěžoval dopisovat implementaci metod, zde je opravdu nepodstatná) :

Kód: [Vybrat]
if( VeterinarniKontrola( HajnyA->get_pes( ) ) != TRUE ) {
  ....
 }
 ...
  for( int i = 0; i != HajnyB->no( ); i++ ) {
    HajnyB->AktualniPes( i );
    if( VeterinarniKontrola( HajnyB->get_Pes( ) ) != TRUE ) {
    /// Neco s tim udelej 
    ...
    }
  }


Výhodou je to, ze programátor primo až při psaní kódu rozhoduje co bude daná třída podporovat, ale myslivec bude vždy myslivec - i presto, ze žádného psa mýt nebude.... Navíc, v zásadách se zásadně nepoužívají virtuální metody, takže nedochází k zbytečnému nafukování výsledného binárního kódu, když změníte zásadu za jinou s jiným rozhraním, sám překladač vás upozorní na změny a nakonec, zásady jsou velice variabilní, takže je lze různě řetězit, nebo kombinovat....

Kód: [Vybrat]
  ...
  HajnyA->JdiNaLov( hon );
  HajnyB->JdiNaLov( hon );
  HajnyC->JdiNaLov( hon ); 
 ...
« Poslední změna: 09. 12. 2010, 00:59:51 od D.A. Tiger »

ondra.novacisko.cz

Re: Jste zastánci OOP programování?
« Odpověď #92 kdy: 09. 12. 2010, 00:53:52 »
Teorie pěkná, ale my jsme ve fázi, kdy máme rozhraní IMyslivec (I znamená Interface a má všechny metody abstraktní). Taky asi nešlo o šablony, protože by to mělo být aplikovatelné i na Javu a jiné jazyky :-)

Takže mám výhradu i k "Traits", protože původní rozhraní Traits nemá a tedy to opět znamená přepsat všechno (i kdyby se tam daly defaultní Traits) ty šipítka se tam psát musí. Možná přes nějakou kombinaci typedefů. Ale jak jsem psal, o to tady nešlo).

Řešení se psí směčkou na místo psa ale beru, je to další řešení, nicméně problém se přesouvá z myslivce na psa. Pokud rozrhaní psa má metody štekej a přines kořist, pak u štekej si dokážu představit, že budou štekat všichni psy, ale jak smečka donese kořist to nevím... ale určitě by to nějak šlo.   ;D

Logik

  • *****
  • 1 034
    • Zobrazit profil
    • E-mail
Re: Jste zastánci OOP programování?
« Odpověď #93 kdy: 09. 12. 2010, 02:14:45 »
Kdo je v té fázi? Já ne :-) Já bych od začátku udělal myslivce s x psy, celou dobu tvrdím, že už při implementaci IMyslivec se měl udělat s více psy, i když byl aktuálně potřeba jen jeden.

To, že když už to někdo zprasil (neuvědomil si, že psů je možné mít více), tak že to někdy nejde s rozumnými (tzn. odpovídajícími zisku) náklady přepsat nepopírám. Akorát tvrdím, že výsledné řešení bude horší (méně čitelné, s větším rizikem chyb a horším laděním), než kdyby byl IMyslivec navržen pořádně od začátku.

--

Udělání ze psa multipsa IMHO není příliš dobrý nápad  - veterinář ho naočkuje, naočkují se tedy všichni psy. Jenže veterinářovi ubyde jen jedna vakcína. A máme zas problém. Pokud má mít myslivec smečku, může jít o dobré řešení (některé pokyny se dají dát opravdu celé smečce), ale musí být všem jasné, že je to smečka (tak to myslím Tiger myslel), a ne ji maskovat za psa.

--

Tiger: To pravidlo se šálkami se mi líbí, to by se mělo tesat do kamene (a těma kamenama pak mlátit po hlavách začínající programátory) :-)
« Poslední změna: 09. 12. 2010, 04:57:04 od Logik »

ondra.novacisko.cz

Re: Jste zastánci OOP programování?
« Odpověď #94 kdy: 09. 12. 2010, 08:31:12 »
Logiku, když pořád trváte na to špatném návrhu už od začátku, tak já jako produkťák nyní budu chtít, aby k veterináři nechodili jen myslivci, ale všichni vlastníci psa.

Co uděláte teď s myslivcema?


D.A. Tiger

  • ****
  • 486
  • Tygr, který žere tučňáka ;-)
    • Zobrazit profil
    • E-mail
Re: Jste zastánci OOP programování?
« Odpověď #95 kdy: 09. 12. 2010, 11:15:16 »
Teorie pěkná, ale my jsme ve fázi, kdy máme rozhraní IMyslivec (I znamená Interface a má všechny metody abstraktní). Taky asi nešlo o šablony, protože by to mělo být aplikovatelné i na Javu a jiné jazyky :-)
Není to teorie :) Používá to knihovna Loki (Alexandrescu - doufám, že to jméno píšu správně), a klientské rozhraní zásad IMyslivec<> lze považovat též za určitou abstrakci. Záleží jen na přístupu. nicméně sám jsem zásady už párkrát ke své spokojenosti použil.

Požadavku na portabilitu do jiných jazyků jsem si nevšiml, reaguji jen na diskuzi kolem  tříd které "umějí běžně více rohraní" - která se vyvinula až do tohoto příkladu. Jak vidíte rozhraní založené na zásadách také, a navíc se obejde bez polymorfních tříd (zasady nesmí být virtuální a nesmějí ani takové funkce obsahovat), nepotřebují k tomu žádný z konverzních "cast" operátorů ( oproti dynamic_cast<>( ) má tu výhodu že není omezena jen na přímou linii hierarchie dědičnosti, a oproti reinterpret_cast<>( ) je přenositelný a korektní )     

Citace
Takže mám výhradu i k "Traits", protože původní rozhraní Traits nemá a tedy to opět znamená přepsat všechno (i kdyby se tam daly defaultní Traits) ty šipítka se tam psát musí. Možná přes nějakou kombinaci typedefů. Ale jak jsem psal, o to tady nešlo).
"Traits"? Jako zvláštnosti? Žádné nevidím...  ;D
Ano, ale píšu - muselo by se to tak navrhnout od začátku. Chybu celého tohoto příkladu vidím už v počátečním návrhu. S dobrým návrhem by bylo řešitelné, aby k veterinářovy chodily všichni lidé - nejen majitelé psa, ale trochu jinou metodou ;) , samozřejmě bez zásahu do třídy IMyslivec.

Představte si, že by produkťák si namyslel, že chce mimo požití více psů při honu taky možnost střílet z různých zbraní a jejich kontrolu, a k tomu měnit uniformu a před honem ji nechat protáhnout čistírnou. Ano s Vaším řešením to upravit lze a rychle, jenže nedej bože aby se tam zanesla chyba a nedej bože aby se to za rok začalo opravovat znova.   

Běžnou chybou programátorů v C++ je, že se totiž hodně rádi nechávají unést myšlenkami OOP, ale (už jsme se toho jednou dotkly) C++ je typový jazyk - a to je jeho síla....   
 
Citace
Řešení se psí směčkou na místo psa ale beru, je to další řešení, nicméně problém se přesouvá z myslivce na psa. Pokud rozrhaní psa má metody štekej a přines kořist, pak u štekej si dokážu představit, že budou štekat všichni psy, ale jak smečka donese kořist to nevím... ale určitě by to nějak šlo.   ;D

och sorry mea culpa. poslední kód měl vypadat takto (i tak se občas projevuje únava :) ):
Kód: [Vybrat]
  HajnyA->JdiNaLov( hon );
  HajnyB->AktualniPes( 1  );   /// Predpokladam, ze jich ma ve smecce vice nez jednoho :) 
  HajnyB->JdiNaLov( hon );
  HajnyC->JdiNaLov( hon ); 

Jinak u zásad jde o to, ze záleží pouze na Vás jak, s jakými psi bude třída IMyslivec operovat ve Vašem kódu. Nabízejí pouze možnost dodat vhodné rozhraní určité třídě a to až při jeho ptřebě. Já tedy vytvořím (navrhnu) Myslivce. Vy jej použijete s multipsem (se vším co s tím souvisí) a třeba Logik jej použije bez psa. Ale myslivec bude vždy myslivec. Veterinář kontroluje psa, ne myslivce, roto taky bude fungovat korektně. Myslivec půjde na hon a pošle tam konkrétního psa - taky ok.  Je to jen a pouze rozhraní - jaké bude a jak jej použijete, je už jen čistě Vaše věc. Rozumíme si?     
« Poslední změna: 09. 12. 2010, 11:43:57 od D.A. Tiger »

D.A. Tiger

  • ****
  • 486
  • Tygr, který žere tučňáka ;-)
    • Zobrazit profil
    • E-mail
Re: Jste zastánci OOP programování?
« Odpověď #96 kdy: 09. 12. 2010, 11:28:49 »
[Logik] Nemyslím, že by Ondra byl začínající programátor (nevypadá na to :D ), ale i tak díky.

Faktem je, že myslet na všechny aspekty nějaké třídy je mnohdy opravdu téměř nadlidský úkol a zohlednit je v nějaké konkrétní (nedej bože abstraktní) deklaraci je potom sisifofský úkol. Jenže pokud se nezvládne už samotný počáteční návrh, je potom dodatečná úprava (pouze prostředky jazyka - nikoliv úpravou původní implementace) hotová pohroma  :'(

Proto je kolikrát podle mě asi nejlepší to co navrhuješ - pokud to jde, upravit, otestovat, odladit a poslat patch. V případě DX ti však nezbývá asi jiná možnost, než násilím nabalovat na původní implementaci další a další vrstvy a modlit se aby to někde neškobrtlo :(
« Poslední změna: 09. 12. 2010, 11:35:14 od D.A. Tiger »

ondra.novacisko.cz

Re: Jste zastánci OOP programování?
« Odpověď #97 kdy: 09. 12. 2010, 12:50:24 »
Není to teorie :)
Tahle diskuze je teorie ... :)

Používá to knihovna Loki (Alexandrescu - doufám, že to jméno píšu správně), a klientské rozhraní zásad IMyslivec<> lze považovat též za určitou abstrakci. Záleží jen na přístupu. nicméně sám jsem zásady už párkrát ke své spokojenosti použil.

Já to znám, knihu mám přečtenou, knihovnu rozebranou do mrtě, některé věcí jsem převzal do svých projektů. Ale nejsem velký zastánce nadužívání šablon, pokud to nemá smysl. A nemá to smysl tam, kde nepotřebuju honit výkon na úkor čitelnosti a flexibilnosti. Prostě běžná rozhraní mám klasicky abstraktní s virtuálními metodami a používám šablony opravdu tam kde to je třeba. Třeba tam, kde si se standardním rozhraním nevystačím, například proto, že rozhraní nejde ani popsat pomocí vyjadřovacích prostředků C++ (například, "objekt musí mít defaultní konstruktor", atd)

Požadavku na portabilitu do jiných jazyků jsem si nevšiml, reaguji jen na diskuzi kolem  tříd které "umějí běžně více rohraní" - která se vyvinula až do tohoto příkladu. Jak vidíte rozhraní

No v Javě je normální že třída "extends" jinou třídu a "implements" pět rozhraní. I více. V C++ sice pro rozhraní klíčové slovo nemáme ale vícenásobnou dědičností lze simulovat z větší části "implements"



založené na zásadách také, a navíc se obejde bez polymorfních tříd (zasady nesmí být virtuální a nesmějí ani takové funkce obsahovat), nepotřebují k tomu žádný z konverzních "cast" operátorů ( oproti dynamic_cast<>( ) má tu výhodu že není omezena jen
na přímou linii hierarchie dědičnosti, a oproti reinterpret_cast<>( ) je přenositelný a korektní )     

Prosím, při přetypování v hierarchii nedymaickou cestou doporučuj static_cast. reinterpret_cast nikdy!


"Traits"? Jako zvláštnosti? Žádné nevidím...  ;D
Přislo mi, že v knize pod slovem "Zásada" se rozumí Traits. Jinak Trait se překládá jako "rys" (traits jsou rysy). Nevím. každý máme jinou terminologii a úplně nejhorší jsou překlady od různých autorů.

Jinak rozhraní program nic nestojí. Implementace rozhraní stojí jednu tabulku VT navíc a dynamic_cast je asi nejnáročnější operace, která tam je (a taky není potřeba vždy).

Používání vícero rozhraní přibližuje C++ spíš k jazykům s dynamickým typování, což se občas může hodit. Sice se s tím asi nedocílí takové výkonnosti jako u šablon, ale je to jako se vším. Otázka ceny.

Psát program celý v šablonách s tím, že místo konkrétního rozhraní tam mám všude T... to se samozřejmě dá, ale člověk se musí připravit na jiné obtíže, například že díky neexistuence konceptů bude často chyby hledat v nějaké desáté úrovni vnoření a louskat hlášky GCC, proč zrovna tenhle objekt nejde do funkce použít a co mu ještě chybí, aby to šlo (třeba nemá defaultní konstruktor)

ondra.novacisko.cz

Re: Jste zastánci OOP programování?
« Odpověď #98 kdy: 09. 12. 2010, 12:53:42 »
Proto je kolikrát podle mě asi nejlepší to co navrhuješ - pokud to jde, upravit, otestovat, odladit a poslat patch. V případě DX ti však nezbývá asi jiná možnost, než násilím nabalovat na původní implementaci další a další vrstvy a modlit se aby to někde neškobrtlo :(

No a teď si vem, že máš v požadavcích BINÁRNÍ kompatibilitu. Nicméně nevidím nutnost simulovat stará rozhraní nějak zásadně. Vždycky to funguje tak, že se simulace šoupne do jiného zdrojáku aby se nepletla s originální obsluhou... a dál se na ní nesahá, jen se pak nakonec přilinkuje. Koho zajímá, že simulace volá simulaci vola simulaci a nakonec volá původní obsluhu? Smyslem je "aby to fungovalo" a ne aby to fungovalo efektivně.

Logik

  • *****
  • 1 034
    • Zobrazit profil
    • E-mail
Re: Jste zastánci OOP programování?
« Odpověď #99 kdy: 09. 12. 2010, 18:28:17 »
No původně to mělo bejt třeba takhle:

Kód: [Vybrat]
IPes {};

IMyslivec
{
   set<IPes> getPsy();
}

Takže pokud budu potřebovat, by vši lidé chodili k veterináři, tak to trochu upravím:
Kód: [Vybrat]
IZvire {};
IPes extends IZvire  {};

IMajitelZvirat
{
   set<IZvirata> getZvirata();
};

IMyslivec extends  IMajitelZvirat
{
   set<IPes> getPsy();
}
V Izvire zadefinuju potřebné metody (popř. je přesunu z IPes). Ve všech psech a myslívcích budu muset sice nadefinovat potřebné metody - což jestli je pořádek v kódu neni problém - ale zas budu mt jistotu, že žádný zvíře nebude naočkovaný.

Pokud bych potřeboval očkovat pouze psy, tak je to ještě jednodušší - udělám rozhraní IMajitelPsu, tam přesunu metodu getPsy z myslivce a myslivce z ni podědím. Všechny lidi pak podědím z majitelů psů. Tady ani dokonce nemusím upravovat ani myslivce, ani psa, pouze ostatní lidi, kteří musí být schopní veterinářovi poskytnout své psy...

Je ještě druhá varianta, která může být někdy užitečná - z IMajitelZvirat nepodědím všechny lidi, ale pouze opravdové majitele zvířat. Na hranicích či u veterináře se pak pomocí RTTI se zeptám, zdali je to majitel zvířat.
To je ale úplně jiná situace, než přetypování IMyslivce na IMyslivce2, protože zde dotaz pomocí RTTI v podstatě supluje metodu mamZvirata(). Buď tedy mám zvířata, nebo neimplementuju toto rozhraní - tercium non datur.
Naopak u myslivců, jak bude vypadat veterinář? Ten se zeptá: jseš IMyslivec? Jestli jo, naočkuje jednoho psa. Pak se zeptá jsi IMyslivec2? Jestli jo, naočkuje všechny psy. A jeden dostane pigáro dvakrát. Jinými slovy: u mého přístupu Majitel zvířat je právě ten, kdo implementuje rozhraní IMajitelZvirat. U Tvého řešení to tak neplatí, může implementovat rozhraní IMyslivec1, IMyslivec2, IMyslivec789 atd...

Jinak, to začínající programátor nebylo na Tebe :-)....
u Tebe už je evidentně pozdě :-D :-D (no offense, only joking :-))
« Poslední změna: 09. 12. 2010, 18:38:04 od Logik »

ondra.novacisko.cz

Re: Jste zastánci OOP programování?
« Odpověď #100 kdy: 10. 12. 2010, 07:57:52 »
Já nevím, ale pořád se točíme v kruhu. Vy neustále dokazujete, že se umíte vyhnout multi-interfacům, že nutíte uživatele vašeho interface neustále přepisovat své objekty, které ho používají. Zapomínáte, že uživatelé mohou být různí, v závisloti na tom, jak populární Vaše knihovna je (po takovýhle tanečcích asi těžko  :D )

Už vůbec se děsím toho, když mi napíšete "vydám patch" a je to. Nevydáte. Patch Vám nepomůže, každý objekt, který rozhraní používá je jiný. Navíc to takhle prostě fungovat nemůže a důkaz je vidět zrovna ve vývoji linuxu. Místo toho, aby se zachovala nějaká základní kompatibilita, tak každý jádro je jiný, po binární stránce úplně, po zdrojákový stránce sice méně často, ale i tak to znamená, že staré ovladače s novým jádrem prostě nepřeložím. Nové ovladače nejsou (autor zaniknul, nebo se věnuje něčemu jinému). žádný patch mi nepomůže, neboť  bych si ho musel napsat sám. A to jen proto, že Linus neuznává OOP, a to ani z pohledu techniky programování, když už to musí psát v Cčku a jako Vy, trvá na tom, že stará rozhraní se musí aktualizěovat a navazující moduly se prostě musí přepsat.

Nejsem si jist, jestli tohle je prostě ta správná cesta. Jistě někdy je třeba udělat radikální řez a vydat Myslivecky Informační Systém 2, který není kompatibilni s verzí 1. Chvíli budete muset udržovat a aktualizovat obě verze, než většina klientů přejdou na verzi 2. A to ta verze 2 musí být fakt dobrá, aby se to těm lidem vyplatilo (přesvědčte linuxové uživatele, aby svá kradená XPčka vyměnla za kradené Sedmičky)

Celý spor vznikl tím, že jsem chtěl dokázat,že není třeba změnu v rozhraní zajišťovat ve všech částech programu, v reakci na opačný názor který tu zazněl jako hlavní kritika OOP (zajímavý je, že to platí i pro klasické ne-OOP programování, viz ten Linux)

Já jsem argumentoval tím, že vždycky se dá vyrobit nové rozhraní. A abych se nedržell u země, vždycky se dá vyrobit úplně nová hierarchie.

Nebo co komu vadí, když můj myslivec bude mít takovou deklaraci
Kód: [Vybrat]
class MujMyslivec implements IMyslivec, IMyslivec2, IKlientVeterinare

Tyhle změny lze provádět inkrementálně, vždy, když chci přidat novou funkcionalitu. Mohu ale samozřejmě nemusím, pokud mi to vyhovuje. Dávám ti, klientovi určitou svobodu v rozhodování. Samozřejmě jde i o cíl systému, který píšu. Pokud z pozice despotického vládce nad mým kódem vydám nařízení po vzoru EU, že každý myslivec musí se svými psy chodit k veterináři, tak si mohu dovolit vynutit si toto rozhraní už na IMyslivec a mám jistotu, že ti, co k veterináři nechodi si prostě v nové verzi neškrtnou, dokud si ty svý myslivce neopraví.

Připomínám, že příklad s myslivcem je jen akademický příklad. Místo myslivce si lze představit třeba rozhraní pevného disku a můžeme se hádat, jestli do tohoto rozhraní přidáme příkaz na označování prázdného bloku pro SSD disky nebo ne. Pokud to totiž uděláme, rozbijeme všechny současné diskové ovladače, pokud k tomu zřídíme nové rozhraní, staré ovladače budou fungovat.

A já považuju programovací styl předpokládající budoucí vývoj stejně důležity jako vy, s tím, že já už dávno vím, že nejsem věštec. Nesnažím se uhodnout, kam půjde vývoj. Nemohu k tomu abych sečetl dvě čísla popsat celý matematický systém, abych pokryl všechny možné budoucí změny... co když místo čísel budem sčítat matice, nebo rovnice?

Logik

  • *****
  • 1 034
    • Zobrazit profil
    • E-mail
Re: Jste zastánci OOP programování?
« Odpověď #101 kdy: 10. 12. 2010, 17:24:11 »
Vraťme se, k začátku diskuse. Tam já jsem tvrdil, že jeden konkrétní navržený interface je dobře, protože je velmi špatně rozšiřitelný. A když ho budu chtít rozšířit. Jestli jste to pochopil jako kritiku OOP, tak si to přečtěte ještě jednou, nebyla to kritika OOP, ale kritika využití dědičnosti na místě, kam prostě dědičnost nepatří. To není nic proti OOP, to je naopak pro OOP. A demonstroval jsem, že z určitých důvodů je ten návrh špatně.

Vy jste na to odpověděl, že není špatně, protože to jde "opravit" pomocí nového rozhraní. A já pouze tvrdím, že to sice jde, že to je někdy i nejlepší řešení, ale že bylo špatně, když se to neudělalo pořádně hned.

Citace
A abych se nedržell u země, vždycky se dá vyrobit úplně nová hierarchie.
Ano jde. Jde psát program pomocí spousty goto. Jde o to, jak bude takový program čitelný. A rozhodně program s méně univerzálními enterfacy bude čitelnější, než program, kde je pro každou věc nadefinovaný nový interface.
Interface je abstrakce, zobecnění. Pokud tedy pro každou věc nadefinuji nový interface, tak kde je ta abstrakce?

Citace
Nebo co komu vadí, když můj myslivec bude mít takovou deklaraci
No vadí tomu spousta věcí. Např. chci objekt na lov. Mám tam poslat IMyslivce,nebo
IMyslivce2?
Chci napsat nové rozhraní na kontrolu všech psů (např. úředníkem). Mám dvě možnosti: První je využít existující rozhraní. Tady ale místo jednoho rozhraní IMajitelZvirat musím kontrolovat rozhraní IMyslivec, IMyslivec2, IKlientVeterinare (a deset dalších).
Navíc, mezi těmi rozhraními není vztah, co když přijde někdo implementující IMyslivec i IKlientVeterinare? Mám kontrolovat objekt pouze skrze jedno z nich, nebo skrze obě? Jak vým, jestli myslivec chodí k veterináři s kočkou, nebo svým mysliveckým psem? Ve výsledku napíšu hromadu zbytečnýho kódu řešící existenci deseti duplicitních rozhraní.

Druhá možnost je napsat nové rozhraní IKontrolovanýClovek. Jenže todle rozhraní nikdo neumí, takže nic nezkontroluji, aniž bych přepsal všechny objekty, které chci kontrolovat - a právě proti tomu brojíte.

No a pak je třetí možnost, že mam v kódu pořádek, IMyslivec byl od začátku poděděnej od IMajitelZvirat, toto rozhraní používá i veterinář a když chci napsat kontrolu úředníkem, opět využiji to samé rozhraní IMajitelZvirat.
Toto řešení je IMHO nejlepší, nejčistší, s nejmenší pravděpodobností výskytu chyb. Také nejvíce odpovídá principu OOP, protože podporuje reusability.

Citace
Vy neustále dokazujete, že se umíte vyhnout multi-interfaců
Už jsem tu jednou psal, nevylučuji, že to řešení s dynamic_castem nebude někdy nejlepší možné. Ani nevylučuji, že se mi návrh nepovede a multi-interfacům se nevyhnu. To ale přeci nepovyšuje bastl na standard.

Když chci přejít řeku a vím, že se tam nebudu vracet, stačí mi doprostřed naházet šutry a přeskákat. To ale neznamená, že mohu prohlašovat, že ty naházené kameny jsou most. Je to bastl - i když v dané situaci nejlepší řešení.
Stejně tak když na 1GB harddisku na data udělám 100MB partition, protože si blbě přečtu velikost - tak pak může být nejlepším řešením udělat ze zbylého místa druhou partition (např. proto, že data nemám kam odzálohovat). To ale přeci neznamená, že by to měl být standardní postup, nebo že řešení se dvěma partition je nejlepší.



Citace
co když místo čísel budem sčítat matice, nebo rovnice?
Právě proto existují určité zásady, jak navrhovat rozhraní - aby se minimalizovala práce při rozšiřování funkčnosti programu. A podle těchto zásad jdou rozhraní posuzovat. Ano, je možné, že budu mít problém, i když ty zásady dodržím, ale ten problém nebude tak často a bude zpravidla daleko jednodušeji řešitelný.
Jednu z těchto zásad sem postnul Tiger. A jelikož IMyslivec tuto zásadu porušuje, jde toto rozhraní označit jako špatně navržené.


« Poslední změna: 10. 12. 2010, 17:29:19 od Logik »

JS

Re: Jste zastánci OOP programování?
« Odpověď #102 kdy: 10. 12. 2010, 17:39:53 »
Ja bych byl rad, kdyby mi ondra.novacisko (nebo jiny zastance OOP) odpovedel na moji otazku, jak podle jeho zkusenosti OOP podporuje reusability. Opravdu me to zajima.

ondra.novacisko.cz

Re: Jste zastánci OOP programování?
« Odpověď #103 kdy: 10. 12. 2010, 22:32:31 »
Logik: Já mám neblahé tušení, že nevíte co rozhraní je. Zvlášť po tom, co se ptáte, kterého myslivce máte poslat na lov. To je jako kdyby jste se ptal, u televize, která má dva video vstupy, kompozitní a SCART, kterým vstupem připojíte video? No samozřejmě tím, který podporuje to video. A pokud podporuje oba, můžete si vybrat.

U úředníka kontrolujícího psy můžete mít také vlastní rozhraní. Je to rozhraní, kterým komunikuje úředník s myslivcem. Dokonce kolikrát ta rozhraní bývají dvě. Někdy musí myslivec komunikovat s úředníkem.

Rozhraní není objekt, je to komunikační protokol. Rozhraní může objekt implemenatovat buď přímo, nebo prostřednictvím proxy objektu, který vystrčí místo sebe. Třeba že by místo sebe na lov poslal kolegu s jedním psem.

A pak jsem pochopil, že Vás trápí název rozhraní. Občas se stane, že během vývoje rozhraní svůj název přestane dokonale vyplňovat. Ale název je jen idenitifikace a nemusí mít význam, Klidně jsem místo IMyslivec mohl vymyslet rozhrani IA8b92cd, jehož specialitou je, že prostřednictvím něho se správce honu dozvídá stav myslivce a jeho psa během honu (třeba polohu myslivce a psa a úspěšnost a podobně). Jiný účel rozhraní nemá.


JS: Re-usability znamená, že z libovolného projektu mohu vykostit libovolnou třídu a tato třída pak může fungovat v jiném projektu. Každá třída může fungovat jako samostatný jedinec nezávisle na okolí. Tuhle vlastnost velice často využívám. Například mám třídu, která maluje na obrazovce bubliny a tuto třídu mám v každém projektu, kde pořtebuju bubliny. V jedné aplikaci jsem si napsal třídu na stahování souboru po internetu. Pak jsem to použil v každém dalším projektu. Jiný příklad, v jedné aplikaci jsem měl ikonku v systray a k tomu napsaný objekt zajišťující obsluhu události s tou ikonou, nastavování ikony a dalších věci. Najednou jsem to potřeboval někde jinde. Tak jsem prostě ty dva soubory (h + cpp) nasdílel do toho nového projektu a bylo to.

Nedokážu si představit, že bych psal jakoukoliv aplikaci tak, aby to byl jeden monolitický návrh. Vždycky to je obrovské množství samostatných spolupracujícíh modulů a jen jedna třída je tam specifická, která to celý zastřešuje. A to je třída tvořící vlastní aplikaci.

Je na místě říct, že OOP podporuje re-usability, ale nemůžu říct, že je jejím garantem. Pořád to záleží na schopnosti programátora a na dobrém návrhu. Nicméně těch pravidel, které člověk musí v projektu dodržet je méně, než u klasického ne-OOP návrhu a navíc to programátora motivuje objekty nezávisle. Nehledě na tom, že člověk snáze navrhne malou černou krabičku kterou pak lépe propojí s jinýma černýma krabičkama, než navrhovat jednu velkou černou krabičku, do který se radši už potom nikdy nepodívám (abych se nezděsil)

D.A. Tiger

  • ****
  • 486
  • Tygr, který žere tučňáka ;-)
    • Zobrazit profil
    • E-mail
Re: Jste zastánci OOP programování?
« Odpověď #104 kdy: 11. 12. 2010, 00:14:12 »
... nejsem velký zastánce nadužívání šablon, pokud to nemá smysl. A nemá to smysl tam, kde nepotřebuju honit výkon na úkor čitelnosti a flexibilnosti. Prostě běžná rozhraní mám klasicky abstraktní s virtuálními metodami a používám šablony opravdu tam kde to je třeba. Třeba tam, kde si se standardním rozhraním nevystačím, například proto, že rozhraní nejde ani popsat pomocí vyjadřovacích prostředků C++ (například, "objekt musí mít defaultní konstruktor", atd)

....

Psát program celý v šablonách s tím, že místo konkrétního rozhraní tam mám všude T... to se samozřejmě dá, ale člověk se musí připravit na jiné obtíže, například že díky neexistuence konceptů bude často chyby hledat v nějaké desáté úrovni vnoření a louskat hlášky GCC, proč zrovna tenhle objekt nejde do funkce použít a co mu ještě chybí, aby to šlo (třeba nemá defaultní konstruktor)

...

Jinak rozhraní program nic nestojí. Implementace rozhraní stojí jednu tabulku VT navíc a dynamic_cast je asi nejnáročnější operace, která tam je (a taky není potřeba vždy).

...
No a teď si vem, že máš v požadavcích BINÁRNÍ kompatibilitu. Nicméně nevidím nutnost simulovat stará rozhraní nějak zásadně. Vždycky to funguje tak, že se simulace šoupne do jiného zdrojáku aby se nepletla s originální obsluhou... a dál se na ní nesahá, jen se pak nakonec přilinkuje. Koho zajímá, že simulace volá simulaci vola simulaci a nakonec volá původní obsluhu? Smyslem je "aby to fungovalo" a ne aby to fungovalo efektivně.

Já nejsem příznivcem nadužívání, nebo protěžování čehokoliv. Všechno co bylo vymyšleno, jsou jen nástroje, které mají za úkol mi nějak ulehčit, zefektivnit, nebo umožnit práci jejich použitím - proto tvrdím, že je pitomostí vždy a všude tvrdošíjně prosazovat objektový, nebo naopak procedurální přístup. To jsou extrémismy a ty jsou od přírody špatné. Nicméně ty nástroje existují a je zas na druhou stranou škoda jich nevyužít, v případech kdy je to vhodné - a ty případy zas určuje konkrétní člověk (lidé), který daný kód tvoří.

Souhlasím s Logikem, že ten akademický příklad je už od začátku špatný, a takový kód je nejlepší omlátit autorovy o hlavu, a pak jej celý přepsat do použitelnější podoby. Jednou z vhodných možností je použít zásad. Žel bohu v praxi (a tady souhlasím s Vámi) je však pro toho kdo s ním pracuje nejlepší na něj nabalit další vrstvy a pak děj se vůle boží. To že tu vrstvu oddělíte do externích modulů, či jakkoliv jinak, však neřeší základní nepříjemnost celého tohoto postupu, a to tu že celou věc znepřehledňuje, zanáší do ní spoustu nových stavů a potencionálních chyb. Vy se v tom možná vyznáte, ale jakmile někdo projekt převezme po Vás, může si jít hodit smyčku (bez urážky, nemyslím tím nic špatného směrem k Vám, vidím to prostě tak i z vlastní zkušennosti).

Celé to připomíná přístup javovských programátorů, kde si vezmete jednu konkrétní funkci z jedné konkrétní knihovny a než se dostanete k tomu co a jak to dělá, prolezete mraky dalších knihoven, vrstev a nadstaveb... A to je špatně (bez ohledu na to zda to někdo řeší či ne, a že to někoho určitě bude zajímat, na to vemte jed ).

Jinými slovy, Vaše řešení podle mě problém se neřeší, jen obchází. Neřeší se nemoc, pouze se odstraňují symptomy.

Navíc je omyl, si myslet, že používání šablon může vést k vyššímu výkonu. Mám zkušenosti i s opakem. Hlavně papačka je to ladit - skoušel jste si někdy seznamy typů z Loki? Krása, ne? (Pravdou je, že tu chybu jsem si tam zanesl sám v jedné ze tříd, ale než jsem ji našel, měl jsem okousaný všechny nehty, tužku, nervy v kýblu a o třicet procent víc šedin)  ;D

Citace
Prosím, při přetypování v hierarchii nedymaickou cestou doporučuj static_cast. reinterpret_cast nikdy!
Operátor reinterpret_cast<>( ) jsem uvedl z důvodu, že umožňuje převod i na jiné nesouvisející struktůry - může v tom být do jisté míry podobnost se zásadou, avšak u zásady to není účel. já jej osobně nevyužívám (nevěřím buď jemu, nebo sobě - vysledek je stejný  :D ). Ovšem pokud je někdo tak dobrý, proč ne... ;)

Citace
Přislo mi, že v knize pod slovem "Zásada" se rozumí Traits. Jinak Trait se překládá jako "rys" (traits jsou rysy). Nevím. každý máme jinou terminologii a úplně nejhorší jsou překlady od různých autorů.

Pokud to dobře chápu, pak rys je něco mezi strategií a zásadou. Poskytuje sice šabloně nové rozhraní, ale jeho zaměřením je interní implementace nějaké funkčnosti - tedy tak nějak jsem to pochopil...

Citace
Používání vícero rozhraní přibližuje C++ spíš k jazykům s dynamickým typování, což se občas může hodit. Sice se s tím asi nedocílí takové výkonnosti jako u šablon, ale je to jako se vším. Otázka ceny.

No, otázka je zda se s tou cenou počítá i do budoucna. Pokud někdo navrhne skříň do níž dám pouze jede hrnek, nebo myslivce, který může mít jen jednoho psa a finito, pak si nejsem tou cenou až tak jist.... Pokud je kód ještě navíc uzavřený, myslím že to může to být v budoucnu velmi drahá záležitost. A určitě sám ze zkušenností víte, že peníze mohou být v takovém případě ještě pořád to nejmenší. Ale - je to asi jen věc pohledu...   
« Poslední změna: 11. 12. 2010, 01:02:45 od D.A. Tiger »