Ahoj, mam dotaz na to jestli existují nějaké zásady, ohledně psaní tříd. Sice je to možná obecnější než jen Net, ale používam teď hlavně ten. Uvítám libovolné postřehy, ale aktuálně mi jde o hlavně o toto. Je špatné, vytvářet složitější konstruktory, spíš než to co třída děla rozložit do metod? Mam například třídu, která dostane nějaké nastavení, kde je např. jen cestu ke zpracovávanému souboru. Je lepší udělat konstruktor, který jen přebere nastavení a pro zpracování souboru je následně nutné zavolat nějakou metodu např. Start? Nebo udělat konstruktor, který přebere nastavení a rovnou zpracuje soubor? Třída samotná jen načítá soubor, nic jiného nedělá.
Fórum › .NET
Návrh třídy
#2 Kit
To byl jen příklad, respektive ona ho klidně může jen načítat, ale nějak se parsuje vstupní formát a nějak se z dat vytváří objekty, nebo se to jen zapíše do databáze. Jde spíš o to, jestli třída určená k jedinému účelu, má (může) to co dělá udělat hned v konstruktoru, nebo jestli má mít spíš nějakou metodu, které to spustí, nebo je to jedno.
public class ImportDat
{
internal readonly string _nazevSouboru;
//rada readonly promennych tridy
//...
//...
//...
public ImportDat(string nazevSouboru)
{
_nazevSouboru = nazevSouboru;
//... treba i delsi kod importu
}
}
Vše v konstruktoru, respektive i z něj volám jednotlivé metody, ale už je to delší... Výhody jsou, že vnitřní proměnné třídy mohou použít atribut readonly a kdo bude třídu používat, tak jen vytvoří objekt, nemusí už hledat jakou metodou to ještě spustit.
public class ImportDat2
{
internal readonly string _nazevSouboru;
//rada promennych tridy
//...
//...
//...
public ImportDat2(string nazevSouboru)
{
_nazevSouboru = nazevSouboru;
}
public void Spust()
{
//... kod importu
}
}
Nebo je čistější udělat maximálně jednoduchý konstruktor a delší kód mít až v metodě, která se musí extra volat?
#3 Kartmen
Jak kdy. Pokud je to třeba config v XML nebo třeba JSON, tak by bylo dobré ho rozparsovat už v konstruktoru nebo ho do něj injektovat zvenčí už rozparsovaný (doporučuji, lépe se to testuje a vyhovuje to SRP).
Zkus si položit otázku, co má konstruktor udělat, pokud parsování selže. Má vytvořit instanci nebo to má odmítnout?
Vstupní data v konstruktoru zásadně neparsuji, pouze si je uložím mezi atributy jako objekt. Obvykle je totiž potřeba jimi iterovat, což by mohl být vážný problém, pokud je smíš ze vstupu číst pouze jednou, což je obvyklý případ.
#4 Kit
Pokud parsování selže, tak standardně dělam nějaký zápis aspoň do logu. Ve většině případů toho co jsem dělal, tak chybné záznamy nejsou problém a běžně se v souboru vyskytují. To se mi ještě nestalo, že bych potřeboval znovu originál (všeho). Pokud jsou data ok, vytvoří se z nich objekt, pokud nejsou, tak se zapíše (chybný) originál. Následně už iteruju jen vytvořené objekty z platných záznamů.
Šlo mi ale o ten konstruktor, jestli je zvěrstvo udělat 50ti, 100, 500, nebo více řádkové konstruktory, nebo je to na vkusu každého programátora?
#1 Kartmen
obecně si to mužeš dělat jak chceš .. protože jak si usteleš tak si pak lehneš ...
ale v konstruktoru má bejt inicializace proměnných, alokace paměti atd .. samostatné zpracování dat má být v metodách třídy ...
#5 Kartmen
Obvykle se to dělá tak, že konstruktor si jen nastaví konfigurkonfigurkokonfigurkonfigurkkonfigurkonfigurkokonfigurkonfiguraci a samotsamotná data jsou pak natažena metodou load() apodapod.
Pokud budeš vždycky dělat new a okamžitě potom Start a jinak je ten objekt k ničemu, tak nemá smysl to rozdělovat.
Kdybys měl nějaký obecný ImportResult DoImport(DataSource, DataSink), tak budiž, ale teď to napiš tak, jak to potřebuješ. Úvahy "co kdyby někdy někdo" jsou k ničemu.
Cest je vícero, záleží co ti vyhovuje a na tom jak s těmi objekty chceš pracovat. Někdy stačí nastavení a výchozí zpracování provést hned v konstruktoru jindy je lepší si ty fáze práce rozložit, obvykle není problém construktor přetížit a udělat jeden základní jen vytvoření objektu a druhý rovnou se zpracováním.
Každopádně bych zpracování oddělil do samostatné metody, tzn
construktor(owner) - vytvoří objekt
constructor(owner, FilePathName) - vytoří objekt nastaví file a přesměruje např na Load
SetFile(FilePathName) - samostatné nastavení souboru
Load - načtení a zpracování souboru
Já mám podobně načítání configurace v delphi z INI file
v construktoru nastavím cestu a název souboru a příznak stavu /ne/načteno
pak mám funkce
fromCFG a toCFG, první načítá druhá ukládá nastavení
funkce mají kolem 100 řádek rozdělených podle sekcí INI po cca 25-30 řádkách
celkem asi 40 klíčů ve 3 sekcích, na načítání klíčů mám podle typu proměnné přetíženou metodu ctiKlic(sekce,klic,proměnná), která vrací zda se povedlo nebo nepovedlo načíst
projdu všechny klíče a pokud se nepovedlo načíst vše co je potřeba, spustí se konfigurační dialog.
#15 MilanL
Jinak každý má svůj způsob práce.
Já se např nejdříve soustředím na funkčnost a až pak na refactoring a optimalizaci.
Ted jak jsem to procházel jsem přišel na další optimalizaci přibližně 1/3 řádek u Loadu a 1/2+ u čtení klíčů by se dala zredukovat.
Hlavní je co největší čitelnost a přehlednost kodu, alespoň pro autora, abys i za 5 let věděl co jak a proč jsi dělal.
#1 Kartmen
eště taková drobnost .. existuje jakési "schéma" návrhu třídy, které by se mělo dodržovat .. 1/ když děláš projekt, kde po tobě nikdo nebude kod používat tak stačí jednodušší varianta (konstruktor - i bez parametrů, public proměnný - vyplní je uživatel neboli to co volá třídu, destruktor, metody - můžou využívat globální proměnné třády a můžou být s minimem vstupních parametrů a samozřejmě nemusíš používat properties) nebo 2/ pokud to po tobě někdo bude číst a hlavně používat třeba jako knihovnu pak je potřeba dodržovat hlavně pravidla vstupu a výstupu proměnných (t.j. používat properties a kontrolu mezí proměnných ) a dobře celou třídu rozdělit do metod a nezapomenout na to udělat zvlášť inicializaci a to i vícekrokovou - rozdělenou na více metod, hlavní blok - rozdělený i na více metod a samozřejmě destruktor a finalizer (pokud je). Nezapomenout na zachycování chyb - t.j. udělat k tomu tzv. ErrClass která bude řešit chyby. To že metoda bude mít víc jak 200 řádků nevadí.
- take se znazim kod delat na 1-2 obrazovku, protoze se snadneji dohledava chyba, zapomenuta zavorka a pod., ale mam i delsi kody, kdyz je potreba
- konstruktor se snazim omezit na prevzeti parametru, ale nekdy je parsuji a nekdy volam dalsi metodu
- pro zpracovani souboru pouzivam vzdy metodu
- Do konstruktoru, vetsinou jako parametr davam app, a jedna z metod je errorAdd, ktera spousti app-> errorAdd a pridava tam jmeno class a jmeno funkce, kde ta chyba vznikla (v php) a casto potrebuji i cislo radku, protoze php nedokaze zobrazit pro sql chybu takovou tu tabulku, ze kterych funkci to vzeslo. Takze, ja mam sice nejakou metodu sql->query, ale nejsem schopen dohledat, ve ktere class jsem ji volal :) Vyhodou vlastni errorAdd je, ze pak tu metodu muzu prepsat, snadno, a presmerovat jinam, kdyz treba tu class budu pouzivat bez hlavni app a vsechnude v class uz nebude treba opravovat volani, ted tam mam $this->errorAdd, ale ve starsich pouzivam jeste $this->APP->errorAdd. Takze tu class pak nemuzes pouzit bez APP
- casto predavam do konstruktoru pro soubory link na CFG['upload'], kde je parametr ['path'], kde mam ulozenou cestu pro nahravani souboru
- a tez pro bezne class v php predavam odkaz na WS class (web-services) nebo SQL a LDAP class. WS je v podstate kod propojujici vyhledavani pomoci sql, ldap a jinych sluzeb a je mozne generovat vystup jako text, php variable, json, xml a jine jednoduche metody. A navic to umi preformatovat parametry z url na volani nektere sluzby. Proste to strasne zjednodusuje vypisy dat a exporty pro ruzne systemy. A neni to slozite si udelat takovou class.
- tez je dobre dodrzet nejaky standard pojmenovani metod. preba sql pouziva
sql: insert, update, delete, replace, select; connect, disconnect;
sockety: open, close, send, receive, connect, disconnect
ldap: ma jeste dalsi ruzna pojmenovani...
file: fopen, fclose, file_get_content, file_put_content (php)
lidi tady zminuji: load :)
A clovek zacne premyslet, proc nepouzili jednotne nazvy, aby si clovek nemusel pamatovat 10.000 pojmenovani, kdyz to vicemene dela totiz :)
Přidej příspěvek
Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku
×Vložení zdrojáku
×Vložení obrázku
×Vložení videa
Uživatelé prohlížející si toto vlákno
Podobná vlákna
Návrh třídy — založil yaqwsx
Navrh tridy — založil Scrat
Změna vlastnosti třídy Windows1 z jiné třídy — založil davedpe
Přístup k objektům jedné třídy ze třídy druhé — založil ProgDan
C++ - Třídy (Export funkcí z třídy do jiné) — založil CodeHustla
Moderátoři diskuze