4 komentářů k článku GRASP – 4 – Polymorphism, Pure fabrication a Indirection:

  1. Radek Miček

    Re: GRASP – 4 – Polymorphism, Pure fabrication a Indirection

    Jinými slovy nikdy neřiďte chování pomocí podmínek testujících typ objektu.

    To se ale běžně dělá třeba v případě výjimek.

    Pokud tento princip není dodržen, tak přidání každé další podtřídy vyžaduje úpravu na všech místech, kde se dříve testoval typ objektu.

    Tahle skutečnost je určitým způsobem symetrická ke skutečnosti, že po přidání abstraktní metody do bázové třídy v jazycích jako C# nebo Java musíme upravit podtřídy, jenž nemají být abstaktní. Stejně jako v případě abstraktních podtříd může kompilátor upozornit na místa, kde testujeme typy objektů a chybí tam test na nějaký (nově přidaný) typ.

    Informace o chování jsou tedy roztříštěné na mnoho míst kódu (což mimo jiné porušuje princip Don’t repeat yourself – DRY).

    Pokud se kód neopakuje, tak DRY není porušen.

    Tento princip říká, že „podtřídy by měly být zaměnitelné s jejich bázovými třídami“.

    LSP mluví o podtypech a ne o podtřídách. Koneckonců aby nějaký typ byl podtyp, tak to nemusí být podtřída (a naopak) – bohužel v mainstreamových staticky typovaných jazycích musí.

    1. Martin Jonáš

      Re: GRASP – 4 – Polymorphism, Pure fabrication a Indirection

      Jako každé pravidlo i polymorfismus má svoje výjimky. V případě zachycování výjimek je typ výjimky hlavním a v podstatě jediným nositelem informace o tom co se stalo.

      To že existují případy vyžadující nevyhnutelnou úpravu na mnoha místech kódu přece neznamená, že se jim nemáme snažit vyhnout. V mnoha případech (vývoj knihoven) pak často ani nemáme nad všemi užitími našich tříd kontrolu.

      DRY bývá porušeno v případech, kdy na mnoha místech používáme stejnou sadu podmínek kontrolujících typ. Jde tedy obvykle o opakující se kód. Opakující se informací je právě seznam známých podtříd.

      S podtypy/podtřídami v LSP máte pravdu.

      1. Radek Miček

        Re: GRASP – 4 – Polymorphism, Pure fabrication a Indirection

        To že existují případy vyžadující nevyhnutelnou úpravu na mnoha místech kódu přece neznamená, že se jim nemáme snažit vyhnout.

        S tím souhlasím. Představte si, že mám třídy pro reprezentaci aritmetických výrazů (jazyk C#, ale závěr se vztahuje i na Javu a jiné jazyky):

        public abstract class Expr { /* obsahuje pripadne abstraktni metody */ }
        public class ExprAdd : Expr { /* uzel reprezentujici scitani */ }
        public class ExprInt : Expr { /* uzel reprezentujici cislo */ }

        Mám minimálně 2 možnosti, jak implementovat vyhodnocení výrazu:

        • Do třídy Expr přidám abstraktní metodu eval, kterou implementuji ve třídách ExprAdd a ExprInt.
        • Nebo vytvořím někde stranou funkci eval, která udělá switch podle typu ExprAdd/ExprInt a provede příslušné vyhodnocení (pokud někomu vadí switch podle typu, tak si místo toho může myslet Visitor – tj. Eval bude třída).

        Nevýhoda první možnosti je v tom, že musím upravit kód na mnoha místech – ve třídách ExprAdd a ExprInt. Navíc je logika vyhodnocení výrazu rozházena po mnoha třídách.

        Nevýhoda druhé možnosti je v tom, že pokud přidám např. ExprMult (uzel pro násobení), tak musím upravit i funkci eval a každou další funkci, která dělá switch dle typu, takže opět musím upravit kód na mnoha místech.

        Pokud nebudu přidávat další uzly, tak je druhá možnost lepší. Pokud nebudu přidávat další metody, tak je první možnost lepší. Programátor by se měl tedy rozhodnout podle toho, zda bude přidávat nové metody nebo nové uzly.

        1. Martin Jonáš

          Re: GRASP – 4 – Polymorphism, Pure fabrication a Indirection

          jak říkáte, vždycky je potřeba se zamyslet nad výhodami a nevýhodami jednotlivých řešení. GRASP principy je vždycky potřeba zvažovat jako celek a dle předpokládaného vývoje.

          Osobně bych ale volil první možnost, protože přidání nového typu výrazu považuji za pravděpodobnější než přidání nové metody do tříd výrazů. (Protected variations)

          Zásada Polymorphism zde jasně preferuje první možnost.

          Dle principu Information Expert (bude probrán příště) by zodpovědnost za výpočet měla mít třída, která má potřebné informace. V našem případě tedy opět třída výrazu.

          Třída Eval by představovala Pure fabrication, kterému bychom se měli vyhnout pokud k tomu není nějaký důvod. Ten by zde ale je možné představit například v efektivitě výpočtu nebo jak píšete v rozhození logiky výpočtu na mnoho míst.

          V zásadě jde o to, že GRASP nám nikdy nedá jasnou odpověď jak to udělat, ale poskytuje vodítka jak o tom jasněji uvažovat. Volba je ale vždy na vývojáři.

Napsat komentář

Tato diskuse je již příliš stará, pravděpodobně již vám nikdo neodpoví. Pokud se chcete na něco zeptat, použijte diskusní server Devel.cz

Zdroj: https://www.zdrojak.cz/?p=3690