V příspěvku se podíváme na vhodnější alternativu za kód stylu if (obj->getItems().size() > 0)
či if (!obj->getItems().empty())
.
Původní kód
Dejme tomu, že máme třídu Directory
, která má metodu getSubdirectories()
. Ta vrátí seznam podadresářů. Dále mějme nějaký konkrétní adresář:
Directory *dir = new Directory("/path/to/directory");
Chcete pak v kódu zjistit, zda má daný adresář podadresáře. Obvykle vídávám jeden z takovýchto kódů:
if (dir->getSubdirectories().size() > 0) if (dir->getSubdirectories().size() >= 1) if (dir->getSubdirectories().size() != 0) if (!dir->getSubdirectories().empty())
Proč takto raději ne?
Z několika důvodů:
- Čitelnost. Abyste pochopili záměr kódu, musíte jej analyzovat. Nejdříve se získají všechny podadresáře. Pak se na podadresářích volá
size()
, což by mělo získat jejich počet. Ten se pak porovná s danou konstantou. Výsledkem je, že seif
provede, pokud je velikost nenulová. Kód sempty()
je na tom o něco lépe, ale i tak je tam ono získávání všech podadresářů. Navíc je tam pak negace, která pochopení opět ztíží. - Duplicitní kód. Podobných kontrol budete mít v kódu více. Na každém místě musíte zopakovat tentýž kód, tedy získání podadresářů a zjištění jejich velikosti.
- Výkonnost. V případě, kdy
getSubdirectories()
vrací výsledný kontejner hodnotou, tak se musí zkopírovat, jenom aby se na něm zavolalosize()
čiempty()
. Výsledná kopie se pak ihned zahodí. To může být zbytečně neefektivní. - Spoléhání se na implementaci. V ono kódu se spoléháte na to, že navrácený objekt má metodu
size()
čiempty()
. Pokud se změní implementace, máte problém. V neposlední řadě se jedná o porušení Deméteřina zákona.
Mimochodem, tento příklad ilustruje porušení principu Tell, don't ask, o kterém jsem psal nedávno.
Jak to udělat lépe?
Přidejte do třídy Directory
metodu hasSubdirectories()
. Kód uživatelů této třídy pak bude vypadat takto:
if (dir->hasSubdirectories())
Nádhera. Čitelné, jasné, krásné. Přesně tak, jak to mám rád.