SOLID
SOLID je označení pro základní principy objektově-orientovaného návrhu. Jejich dodržování má vést k pochopitelnějšímu, flexibilnějšímu a lépe udržovatelnějšímu kódu.
- Single Responsibility Principle (SRP)
- každá třída nebo funkce by měla mít na starost právě jednu věc
- Open-Closed Principle (OCP)
- každá třída by měla být otevřená pro rozšíření, ale uzavřená pro modifikaci
- (rozšíření by mělo spočívat v implementaci nového kódu, ne v modifikaci existujícího kódu)
- Liskov Substitution Principle (LSP)
- funkčnost rozhraní/programu se nesmí rozbít, pokud místo rodičovské třídy dosadíme jejího potomka
- Interface Segregation Principle (ISP)
- kód by neměl záviset na metodách, které nepoužívá
- (více menších rozhraní je lepší než jedno velké rozhraní)
- Dependency Inversion Principle (DIP)
- vysokoúrovňové moduly by neměly záviset na nízkoúrovňových modulech, oba typy modulů by měly záviset na abstraktních rozhraních
- abstrakce by neměly záviset na implementačních detailech, ale detaily by měly záviset na abstrakcích
Viz Dmitri Nesteruk - Design Patterns in Modern C++: Reusable Approaches for Object-Oriented Software Design
Návrhové vzory (design patterns)
- Je dobré používat standardní řešení/knihovny apod. protože víc lidí chápe co děláte a snáz se to vysvětluje. Na druhou stranu neroubujte standardy tam, kde se nehodí, jen proto, abyste použili něco standardního.
- Existují určité problémy, které musí řešit téměř každá aplikace a vyplatí se udělat si už ze začátku nějaký systém, který budete stále používat. Jde hlavně o problémy:
- Alokace paměti – na 99% asi bude stačit standard systému, ale někdy se vyplatí použít vlastní
- Uvolňování paměti/zdrojů, jakým způsobem poznáte, že nějaké data/soubor/spojení do databáze už nejsou potřeba a máte je uvolnit
- Cachování zdrojů – pokud je možnost, že nějaký soubor/data/objekt bude potřeba znova po té co aktuálně už potřeba není může se vyplatit ho místo smazání cachovat
- Přístup k datům z pevného disku – měl by být přes nějaký centrální objekt, aby se dalo snadno zjistit, které části aplikace něco potřebují (případně logovat)
- Logování – zda a jak hodláte vypisovat informace o běhu/chyby apod.
- Ukládání (serializace) dat, ať už do souboru nebo databáze
- Vícevláknová architektura pokud ji používáte
- Synchronizace více počítačů po síti pokud to aplikace vyžaduje
- Pokud pro řešení nějakého problému není k dispozici vhodná knihovna, stejně je vhodné používat často používané postupy, aby byl kód přehledný i pro ostatní programátory.
- Návrhové vzory usnadňují práci (neobjevuj kolo), zpřehledňují kód, brání vzniku chyb, …
- Pozor na overengineering – někdy je lepší si rychle „nabastlit“ kus kódu, než trávit čas vymýšlením dokonale flexibilního kódu, který je v souladu se všemi principy a návrhovými vzory.
Prostá funkce
- killer feature of the C++ language
- když nevíte, jak něco naprogramovat, vytvořte funkci
- DRY
Knihovna
- způsob organizace funkcí, struktur, tříd do souborů
namespace
pro vytváření „modulů“ – označení souvisejících funkcí/struktur/tříd
RAII (Resource Acquisition Is Initialization)
- využití konstruktoru a destruktoru pro zajištění správné správy dynamických zdrojů
- volání destruktoru je zajištěno i při vzniku výjimky
- alokace/dealokace, otevření/zavření souboru, správa komunikačního socketu, zámky pro komunikaci mezi vlákny, vytvoření/odstranění dočasného souboru/adresáře, atd.
Smart pointer
- různé způsoby správy dynamických zdrojů pomocí RAII
- původně vznikly pro dynamickou alokaci/dealokaci, ale pomocí vlastní třídy
Deleter
lze modifikovat chování pro libovolný účel - standardní knihovna obsahuje:
std::unique_ptr
,std::shared_ptr
,std::weak_ptr
- další implementace: např. Boost
Iterator
- koncept ze standardní knihovny: Iterator (další koncepty: forward iterator, bidirectional iterator, random access iterator)
- zobecnění použití ukazatele pro přístup k prvkům pole
- slouží k procházení prvků datových struktur: např.
for (auto it = data.begin(); it != data.end(); it++)
- umožňují zkrácený zápis pomocí range-based for loop:
for (auto v: data)
(zde alev
není iterátor, ale přímo hodnota z datové struktury) - obecný iterátor je instance nějaké „proxy class“ (to je taky jeden z návrhových vzorů)
- někdy nemusí být použití iterátorů vhodné – např. v některých případech může být vytváření iterátorů neefektivní a jiné způsoby procházení datové struktury můžou být efektivnější
- Writing a custom iterator in modern C++