OOP a pravidla pro konstruktor

anonym

OOP a pravidla pro konstruktor
« kdy: 02. 06. 2018, 14:25:35 »
Došel jsem ze zkušeností k tomu, že konstruktor je třeba výlučně používat pouze k nasetování stavu objektu. Je chyba v konstruktoru provádět jakékoliv výpočty atp., vždycky jsem se tím dostal do problémů a musel jsem to refaktorovat. Máte stejný poznatek? A pokud ano, jak jste na to přišli? Nečetl jsem o tom nikdy v žádné literatuře a přitom mi to přijde jako důležité pravidlo.
« Poslední změna: 03. 06. 2018, 18:55:44 od Petr Krčmář »


uuuuuuuu

Re:OOP a pravidla pro kontruktor
« Odpověď #1 kdy: 02. 06. 2018, 14:33:39 »
Dej vsecko do konstruktoru, usetris dalsi metody :-)

Franta <xkucf03/>

Re:OOP a pravidla pro kontruktor
« Odpověď #2 kdy: 02. 06. 2018, 17:46:29 »
Pokud si třída drží stav a inicializuje nějaké další objekty/proměnné, které se používají ve více metodách, tak to potřebuješ inicializovat před voláním těch metod – což se typicky dělá v konstruktoru.

Jsou i další možnosti: můžeš použít líné vyhodnocování a ke všem těm instančním proměnným přistupovat přes gettery a inicializovat je při prvním použití. Teoreticky ti to může ušetřit nějaké zdroje (co není potřeba, to se neinicializuje). Ale na druhou stranu si musíš dát pozor na pořadí (aby na sobě jednotlivé inicializace nezávisely nebo se volaly ve správném pořadí) a taky to vede k hůře odhalitelným chybám – když se něco vysype, tak ne při volání konstruktoru (kde by to člověk čekal, protože tam zadal ty parametry, které způsobily chybu), ale až někdy později, při volání nějaké metody, která s tím nesouvisí. Můžeš mít objekt ve špatném/nepoužitelném stavu a nevědět o tom (přijde se na to až při volání jeho metod).

Další možnost je návrhový vzor stavitel (builder) a případně i fluent interface. Pomocí volání různých metod postupně naparametrizuješ/postavíš daný objekt a až voláním poslední metody k němu získáš přístup – v tu chvíli budeš mít plně funkční objekt.

Nicméně (alespoň v jednodušších případech) bych nezavrhoval tu úplně obyčejnou inicializaci v konstruktoru a nedělal to složitější, než je potřeba. Při rozhodování je dobré si položit otázky:
 - Jaký je očekávaný budoucí rozvoj dané třídy?
 - Používá se jen v rámci daného projektu/modulu, nebo slouží jako knihovna/API pro ostatní týmy a nezávislé projekty/moduly? Tzn. můžu danou věc refaktorovat, aniž bych se musel domlouvat s někým dalším? Pokud ano, tak bych se držel co nejjednodušších řešení – složitěji to totiž můžu udělat kdykoli později. Naopak pokud vystavuji veřejné API, na které se ostatní budou napojovat a zvyknou si na něj, tak je lepší to dělat rovnou nějakým robustnějším způsobem (s ohledem na budoucí požadavky a změny), aby se rozhraní už nemuselo měnit a aby ses na těchto změnách nemusel domlouvat s ostatními (ta koordinace a komunikace sežere dost času a energie a někdy možnost změny úplně pohřbí).

Kit

Re:OOP a pravidla pro kontruktor
« Odpověď #3 kdy: 02. 06. 2018, 18:18:13 »
Konstruktor by měl uvést objekt do výchozího konzistentního stavu. Zpravidla to vypadá tak, že pouze umístí předané parametry do lokálních atributů a hotovo. Obvykle ta data ani nevaliduji, protože v tu chvíli nevím, která pravidla k tomu budu potřebovat.

SPECZ

Re:OOP a pravidla pro kontruktor
« Odpověď #4 kdy: 02. 06. 2018, 18:53:24 »
Trošku OT, ale téma mi připomnělo:

Stížnost mého kolegy, programátora:

KURVA! KURVA! KURVA! Predchozi programator vyrobil specialni tridu jen na prevadeni rychlosti z kilometru/sec. na metry/sec., dalsi specialni tridu na vypocet, jak dlouho trva presun danou rychlosti po usecce dane delky (jedina metoda teto tridy, ktera to vypocita, navic prijima rychlost v m/s, vzdalenost v metrech a vraci milisekundy)... ale uz si nezkontroluje, jestli mu nekdo do vstupnich souboru nepodhodil nulovou rychlost vozidla!
Takze klidne vypocita "potrebny cas", podeli nulou, vyjimka se zignoruje, prevede to nekonecno na long (to ty milisekundy), vyjde mu cas prekracujici stari vesmiru, klidne ho vrati dal, ten cas se pouzije jako simulacni cas, kdy ma prijit udalost "dosazeno cile", pricte se k nemu aktualni simulacni cas, pretece to, vyjde minus .. ten minus se pak prevede na dny a pak to zkolabuje na tom, ze vysledek neni z rozsahu 0..6, coz jsou platne dny v tydnu ...
kdo tohle pouzije na modelovani realne dopravy, ten nebude do smrti veselej ...


BoneFlute

  • *****
  • 1 981
    • Zobrazit profil
Re:OOP a pravidla pro kontruktor
« Odpověď #5 kdy: 02. 06. 2018, 20:07:32 »
Došel jsem ze zkušeností k tomu, že konstruktor je třeba výlučně používat pouze k nasetování stavu objektu. Je chyba v konstruktoru provádět jakékoliv výpočty atp., vždycky jsem se tím dostal do problémů a musel jsem to refaktorovat. Máte stejný poznatek? A pokud ano, jak jste na to přišli? Nečetl jsem o tom nikdy v žádné literatuře a přitom mi to přijde jako důležité pravidlo.

Ano, setkal jsem se s tímto trvrzením. Za mě mohu říct, že není správně. A doufám, že se moc nerozšíří.

gfdg

Re:OOP a pravidla pro kontruktor
« Odpověď #6 kdy: 02. 06. 2018, 20:20:00 »
Došel jsem ze zkušeností k tomu, že konstruktor je třeba výlučně používat pouze k nasetování stavu objektu. Je chyba v konstruktoru provádět jakékoliv výpočty atp., vždycky jsem se tím dostal do problémů a musel jsem to refaktorovat. Máte stejný poznatek? A pokud ano, jak jste na to přišli? Nečetl jsem o tom nikdy v žádné literatuře a přitom mi to přijde jako důležité pravidlo.

Ano, setkal jsem se s tímto trvrzením. Za mě mohu říct, že není správně. A doufám, že se moc nerozšíří.

V C++ to podle me plati, protoze v konstruktoru by se nemely volat virtualni metody. Cili pokud konstruktor neco pocita a potomek by chtel pocitat neco jineho, tak smula.

gll

  • ****
  • 429
    • Zobrazit profil
    • E-mail
Re:OOP a pravidla pro kontruktor
« Odpověď #7 kdy: 02. 06. 2018, 20:27:30 »
best practice je nepsat konstruktory vůbec, nechat je generovat automaticky. Validace a inicializace definovat pro jednotlivé atributy. Potom máte u všech objektů standardizované parametry a chybové hlášky. V Pythonu používáme všude knihovnu attrs.

Onestone

Re:OOP a pravidla pro kontruktor
« Odpověď #8 kdy: 02. 06. 2018, 21:03:52 »
Trošku OT, ale téma mi připomnělo:

Stížnost mého kolegy, programátora:

KURVA! KURVA! KURVA! Predchozi programator vyrobil specialni tridu jen na prevadeni rychlosti z kilometru/sec. na metry/sec., dalsi specialni tridu na vypocet, jak dlouho trva presun danou rychlosti po usecce dane delky (jedina metoda teto tridy, ktera to vypocita, navic prijima rychlost v m/s, vzdalenost v metrech a vraci milisekundy)... ale uz si nezkontroluje, jestli mu nekdo do vstupnich souboru nepodhodil nulovou rychlost vozidla!
Takze klidne vypocita "potrebny cas", podeli nulou, vyjimka se zignoruje, prevede to nekonecno na long (to ty milisekundy), vyjde mu cas prekracujici stari vesmiru, klidne ho vrati dal, ten cas se pouzije jako simulacni cas, kdy ma prijit udalost "dosazeno cile", pricte se k nemu aktualni simulacni cas, pretece to, vyjde minus .. ten minus se pak prevede na dny a pak to zkolabuje na tom, ze vysledek neni z rozsahu 0..6, coz jsou platne dny v tydnu ...
kdo tohle pouzije na modelovani realne dopravy, ten nebude do smrti veselej ...
Modelování dopravy a vůbec cokoliv důležitého by měli psát jen aspoň průměrně inteligentní lidé s odpovídajícím vzděláním. Kdo na to pustí pologramotné retardované tele, nemůže se divit.

anonym

Re:OOP a pravidla pro kontruktor
« Odpověď #9 kdy: 02. 06. 2018, 22:44:17 »
Došel jsem ze zkušeností k tomu, že konstruktor je třeba výlučně používat pouze k nasetování stavu objektu. Je chyba v konstruktoru provádět jakékoliv výpočty atp., vždycky jsem se tím dostal do problémů a musel jsem to refaktorovat. Máte stejný poznatek? A pokud ano, jak jste na to přišli? Nečetl jsem o tom nikdy v žádné literatuře a přitom mi to přijde jako důležité pravidlo.

Ano, setkal jsem se s tímto trvrzením. Za mě mohu říct, že není správně. A doufám, že se moc nerozšíří.

Já vždycky když jsem sloučil inicializaci a výpočet do konstruktoru, dostal jsem se do slepé uličky - jednak v kódu a jeho struktuře samotné, tak při unit testování. Ani validaci bych nedělal v konstruktoru, jak říká Kit. Když potřebuju validovat nějaká data, udělám z té třídy pojo a validaci té třídy dám bokem do jiné třídy.

anonym

Re:OOP a pravidla pro kontruktor
« Odpověď #10 kdy: 02. 06. 2018, 22:47:22 »
Viz to Unit testování: třída bude mít private metody a já je budu muset mockovat. Jak budeš mockovat, když už při zavolání konstruktoru se ti spustí výpočetní logika?

xxxxx

Re:OOP a pravidla pro kontruktor
« Odpověď #11 kdy: 02. 06. 2018, 22:54:35 »
Došel jsem ze zkušeností k tomu, že konstruktor je třeba výlučně používat pouze k nasetování stavu objektu. Je chyba v konstruktoru provádět jakékoliv výpočty atp., vždycky jsem se tím dostal do problémů a musel jsem to refaktorovat. Máte stejný poznatek? A pokud ano, jak jste na to přišli? Nečetl jsem o tom nikdy v žádné literatuře a přitom mi to přijde jako důležité pravidlo.

Ano, setkal jsem se s tímto trvrzením. Za mě mohu říct, že není správně. A doufám, že se moc nerozšíří.

V C++ to podle me plati, protoze v konstruktoru by se nemely volat virtualni metody. Cili pokud konstruktor neco pocita a potomek by chtel pocitat neco jineho, tak smula.
Výpočty klidně, ale hodně s mírou a člověk musí vědět co dělá. Což je u C(C++) stejně povinnost.

U C++ navíc přibývá problém s tím, že u statických class probíhá volání konstruktorů ještě před main. Teď už sice platí, že okolí už je jinak plně inicializované (výjimky, thread variable, new, malloc ...) (možná jen nějaký starý překladač by mohl mít problémy), ale ani pořadí volání jednotlivých statických konstruktorů není definované (občas překladač nabízí, ale bývá to i verze od verze jiné).

A vyloučit možnost, že někdy někdo (nebo i já, pokud zapomenu) použije class jako static, tak úplně nejde. Pokud vím o závislostech a počítat a využívat je musím, pak už zbývá jen to nějak obejít. Třeba lazy initialization, nifty counter / Schwarz counter, ... ale to bývá cesta do pekel.

P.S.: NEsouhlasím se zpracováním osobních údajů v rozsahu v odkazovaném textu u checkboxu, který jde NAD rámec údajů nezbytných pro technické zpracování

BoneFlute

  • *****
  • 1 981
    • Zobrazit profil
Re:OOP a pravidla pro kontruktor
« Odpověď #12 kdy: 03. 06. 2018, 01:18:20 »
Došel jsem ze zkušeností k tomu, že konstruktor je třeba výlučně používat pouze k nasetování stavu objektu. Je chyba v konstruktoru provádět jakékoliv výpočty atp., vždycky jsem se tím dostal do problémů a musel jsem to refaktorovat. Máte stejný poznatek? A pokud ano, jak jste na to přišli? Nečetl jsem o tom nikdy v žádné literatuře a přitom mi to přijde jako důležité pravidlo.

Ano, setkal jsem se s tímto trvrzením. Za mě mohu říct, že není správně. A doufám, že se moc nerozšíří.

Já vždycky když jsem sloučil inicializaci a výpočet do konstruktoru, dostal jsem se do slepé uličky - jednak v kódu a jeho struktuře samotné, tak při unit testování. Ani validaci bych nedělal v konstruktoru, jak říká Kit. Když potřebuju validovat nějaká data, udělám z té třídy pojo a validaci té třídy dám bokem do jiné třídy.

Rozumím. Domnívám se, že ten problém bude jinde.

Inicializace a výpočet klidně do konstruktoru, pokud to zajistí, že ten objekt bude mět méně možnejch stavů.
To, zda budeš validovat nějaké data přímo, nebo si na to vytvoříš spešl objekt je fuk, ale stejně to hodím čím dřív tím líp, takže do konstruktoru.

Pokud máš pocit, že jsi se dostal do slepé uličky, tak si nějak poznamenej konkrétní případ, a nabídni to k diskusi, jak by to řešili ostatní. Pokud jde o mě, tak vyvozuješ zbrklej závěr, který nepovede k lepšímu kódu.

BoneFlute

  • *****
  • 1 981
    • Zobrazit profil
Re:OOP a pravidla pro kontruktor
« Odpověď #13 kdy: 03. 06. 2018, 01:20:10 »
Viz to Unit testování: třída bude mít private metody a já je budu muset mockovat. Jak budeš mockovat, když už při zavolání konstruktoru se ti spustí výpočetní logika?

Jak chceš mockovat privátní metody?
Jak to souvisí s tím, že při konstruktoru se ti spustí výpočtení logika?
Jak to jakkoliv komplikuje jednotkové testování?

Nechápu.

BoneFlute

  • *****
  • 1 981
    • Zobrazit profil
Re:OOP a pravidla pro kontruktor
« Odpověď #14 kdy: 03. 06. 2018, 01:51:16 »