Skip to content

Instantly share code, notes, and snippets.

@JanTvrdik
Created April 26, 2012 20:15
Show Gist options
  • Save JanTvrdik/2502747 to your computer and use it in GitHub Desktop.
Save JanTvrdik/2502747 to your computer and use it in GitHub Desktop.

Existuje třída HtmlNode, od které dědí třídy HtmlElement a HtmlTextNode.

Takže např. následující HTML kód

<div>
    First text
    <strong>Foo</strong>
    Second text
</div>

Bude reprezentován jako

HtmlElement(div)
    HtmlTextNode(First text)
    HtmlElement(strong)
        HtmlTextNode(Foo)
    HtmlTextNode(Second text)

Potřebuji naparsovaný a v pamětí namodelovaný kód vypsat pěkně zformátovaný. Podle Single responsibility principle by třídy HtmlElement a HtmlTextNode neměli vědět, jak se mají vypsat. Měla by tedy existovat nějaká další třída HtmlPrinter, která by měla metodu void Print(const HtmlNode*) const. Problém je, že uvnitř této metody by bylo nutné použít dynamic cast, což je v C++ považováno za známku špatného objektového návrhu.

@JakubTesarek
Copy link

V C++ jsem nikdy neprogramoval, dělám PHP + javu, ale nějak nerozumím tomu, proč by bylo to, že bude ten objekt znát svoji řetězcovou reprezentaci porušením SRP. Jasně, kdyby se i sám vypisoval, pak je to zcela očividné porušení single responsibility. Ale v podstatě to není nic jiného, než kontejner na data, proč by tedy neměl vědět, jak ta data mají vypadat? Třídy podle mě můžou obsahovat metody jako getHash, compareTo nebo toString a za porušení SRP se to nepovažuje. Ale třeba se pletu a dělám to celou dobu blbě.

Každopádně, pokud bych si měl vybrat mezi porušením SRP a dynamic castem, volil bych spíš takovéhle skoro neznatelné porušení SRP. Dynamic cast se totiž hůře refaktoruje a přináší víc "záludných" problémů. Porušení SRP se naproti tomu opravuje celkem jednoduše. Každopádně, nemyslím si, že by popisovaný příklad byl porušením SRp ale samozřejmě neznám kontext, takže se to špatně určuje.

@JanTvrdik
Copy link
Author

Tady je problém v tom, že ta metoda Print() nebo ToString() musí obsahovat spoustu logiky starající se o pěkné formátování. V budoucnu bych chtěl, aby se způsob formátování dal různě ponastavovat, čímž kód ještě nabobtná. Z hlediska SRP mi prostě připadá lepší, kdyby se o formátování starala jiná třída. Nicméně dynamic cast mi připadá jako ještě horší řešení, takže zatím se vydávám cestou virtuální metody Print ve třídě HtmlNode. Snad mě časem napadne lepší řešení.

@JakubTesarek
Copy link

Rozhodně bych se přimlouval za to, vyhnout se dynamic castu. Jakmile ho kdekoli vidím, už předem vím, že s tím budou problémy. To hezké formátování nejsi schopen udělat někde jinde? Prostě to pomocí nějakého HtmlFormateru ještě jednou přerovnat i za cenu nižší efektivity?

Pokud myslíš tím hezkým formátováním to, že zanořené značky by měly být odsazené, tak to je celkem problém. Protože Node by podle mě klidně mohl znát svoji textovou reprezentaci, ale už ne to, že je někde zanořený a jak hluboko. Co to zkusit celé otočit a udělat to podobně jako SAX? Prostě inversion of control. Na HtmlPrinter dostane zprávu, že začíná zanořený tag, tak vytiskne odsazení, pak dostane zprávu, že má následovat řetězec, pak že je konec tagu ... doufám že jsem to napsal srozumitelně. Postnul bych kód, ale z C++ neznám ani základní syntaxi.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment