\

Školení Návrhové vzory, OOP a UML


 Thursday, 27 April 2006
Řešení hádanky z 18-.4. - vztahy Include, Extend v případech užití

Protože kolegové v diskuzi pod původním spotem podrobně rozebrali všechny aspekty vztahu Include a Extend v případech užití,  je tento můj spot z větší části sumarizující. V čem tedy byl "chyták"? Cílem hádanky bylo upozornit na to, že vztahy Include a Extend nemusejí být tak jednoduše rozpoznatelné, jak se dočtete v různých rychlopříručkách,  a také jsem chtěl, abyste si všimli, že vztah Extend bylo bylo příjemné zpřesnit tím, co sám pro sebe nazývám "anonymní datové sloty".

Tak toto byl začátek dvoustránkového spotu, který se mi podařilo omylem smazat. :-( Protože už se mi nechce teď psát celý spot znovu, tak jen v krátkosti zrekapituluji, čeho se hádanka týkala.

Specifikace UML popisuje vztahy Include a Extend takto:

"Include is a directed relationship between two use cases, implying that the behavior of the included use case is inserted into the behavior of the including use case. The including use case may only depend on the result (value) of the included use case. This value is obtained as a result of the execution of the included use case."

"This relationship specifies that the behavior of a use case may be extended by the behavior of another (usually supplementary) use case. The extension takes place at one or more specific extension points defined in the extended use case. Note, however, that the extended use case is defined independently of the extending use case and is meaningful independently of the extending use case. On the other hand, the extending use case typically defines behavior that may not necessarily be meaningful by itself. Instead, the extending use case defines a set of modular behavior increments that augment an execution of the extended use case under specific conditions. Note that the same extending use case can extend more than one use case. Furthermore, an extending use case may itself be extended."

 

V hádance nemohl být vztah mezi případem užití 'Založení objednávky' a 'Platba kartou' Include ani Extend. Include nelze použít, protože máme i jiné typy plateb, a případ užití Platbu kartou tedy nelze vložit povinně (dalším typem platby bude třeba dobírka - žádné záludnosti ohledně plateb jsem přichystány neměl, jen jsem chtěl, abyste se jako správní analytici pídili po podrobném zadání :-) ). Nejedná se ale ani o vztah Extend, protože rozšířený případ užití nijak nezávisí na rozšiřujícím případu užití a nemůže číst žádné jeho "návratové hodnoty"  - pro nás to znamená, že nezjistíme, jestli platba prošla.

Řešením je vytvoření nového abstraktního případu užití nazvaného třeba 'Kontrola platby', který přes vazbu Include provážeme s případem užití 'Založení objednávky' . Konkrétními potomky budou "Kontrola platby kartou", "Kontrola ostatních typů plateb". Vazba Include nám dovoluje číst návratovou hodnotu vloženého případu užití. V alternativním toku událostí případu užití  'Založení objednávky' podle vybraného typu platby vložíme konkrétní případ užití a dle výsledku vkládaného případu užití dokončíme hlavní tok událostí. Když neprojde platba kartou, můžeme zákazníkovi nabídnout výběr jiného typu platby.

Hlavně ale platí - celá hádanka i její řešení je jen hříčka bez užitku pro zákazníka, která demostruje, jak lze i méně časté vztahy řešit běžnými výrazovými prostředky jazyka UML. Stále platí, že vazby Include, Extend ani gen-spec zákazníkovi raději moc neukazujte, jestliže  nechcete zbytečně trávit čas vysvětlováním vztahů, které jsou pro projekt málo podstatné a pro zákazníka samotného většinou jen iritující.



Thursday, 27 April 2006 18:25:16 (Central Europe Standard Time, UTC+01:00)       
Comments [13]  Programátorské hádanky | UML


 Wednesday, 19 April 2006
Sedm dobrých programů (nejen) pro MDA Vario
MDA

Tady je malý výběr z programů, které mám nainstalovány na MDA Variu (Qtek 9100).

 

  1. Navigační aplikace TomTom - pro Čechy i další země jedna z nejlepších navigačních aplikací. S pomocí TomToma jsem najezdil už pěkných pár tisíc km a kromě drobných nedostatků, které se najdou v každé aplikaci, musím jeho autory jen chválit. Bez navigace už nikdy jezdit nebudu a papírové mapy považuji již jen za vysloužilou archiválii hodnou možná tak piety, ale nehodnou další aktivní služby. :-) Výhodou TomToma také je, že se dá již koupit oficiálně i v Čechách - viz třeba obchod společnosti Sunnysoft. Pro Čechy doporučuji sehnat mapový balík PL-CZ-SK-HU verze 645.
  2. MChat - zdarma dostupný a přijatelně spolehlivý klient pro ICQ.  Ovládání by mohlo být lepší - v aktuální verzi se neobejdete bez vytažení dotykového pera, což trochu degraduje požitek z pohodlí integrované HW klávesnice. :-(
  3. eWallet - graficky povedený program pro správu "tajných informací" jako  jsou přístupová hesla, PINy nebo  údaje o platebních kartách. Jen nesmíte zapomenout to jediné důležíté vstupní heslo do programu. :)
  4. CheckNotifications - program pro zobrazení notifikací, který červeně odliší duplicitní notifikace a jedním tlačítkem v něm také duplicitní notifikace smažete. Notifikace je operačním systémem Windows Mobile založena interně vždy, když potřebujete systému "říci" - v určitou hodinu nebo po výskytu nějaké události (třeba probuzení systému) něco udělej (zapni budík, spusť program...).
  5. SmartsKey  - volně dostupný program, který KONEČNĚ z MDA Vario udělá zařízení, jež se dá ovládat jednou rukou. Jednou z nejlepších funkcí je, že tlačítka na zvyšování/snižování hlasitosti můžete v jiných aplikacích než jsou telefon a Today obrazovka používat pro posun textu. Funkce SmartsKey by měly být integrovány ve Windows Mobile hned od Microsoftu a nechápu, proč tomu tak není.
  6. SPB Diary - program, který na obrazovku Today integruje úkoly, kalendář, kontakty a poznámky. Integrace je oproti pluginům dodávaným přímo s Windows Mobile mnohem dokonalejší a většinu činností s PIM položkami zvládnete rovnou z Today obrazovky. Nechcete-li požívat funkcemi překypující programy, jakými jsou Pocket Informant nebo Agenda Fusion, a dáváte přednost jednoduššímu uživatelskému rozhraní, je program SPB Diary dobrá volba.
  7. SPB Pocket Plus  - SPB Pocket Plus je program od firmy, která vytvořila SPB Diary,  a i přes nějaké chybky, na které narazíte při delším používání, jde o program, který by měl mít nainstalován každý majitel zařízení s Windows Mobile. Pocket Plus umožní vytvářet zástupce na programy i různé speciální "akce" (regulace podsvícení displeje apod.) přímo na Today obrazovce v uživatelsky definovaných záložkách, do horní části obrazovky přidají nevtíravý indikátor stavu baterie, obsahují skvělý task manager a mohou spustit zařízení v nouzovém režimu + další menší vylepšení systému. Nouzový režim oceníte hlavně tehdy, když si nainstalujete nějaký špatně napsaný Today plugin, který způsobí, že zařízení po "soft resetu" nenaběhne. Když byste neměli SPB Pocket Plus, jediným řešením je "hard reset" se všemi následujícími otravnými novými instalacemi všech programů. Pozor na to, že nouzový režim na starších verzích SPB Pocket Plus nemusí na Variu fungovat správně. Paradoxně pak je zapnutá podpora nouzového režimu příčinou vynuceného "hard resetu".


Wednesday, 19 April 2006 12:03:37 (Central Europe Standard Time, UTC+01:00)       
Comments [9]  Mobilitky


 Tuesday, 18 April 2006
Zajímavý dotaz (hádanka) na případy užití v UML - vztah Include, Extend, anebo ...?

Po základní analýze jste zjistili, jak zákazníci vašeho klienta vytvářejí objednávky:

"Zákazník v našem obchodě vybírá zboží a poté si může vybrat, jak jej uhradí. Jedním z možných typů platby je platba kartou. K založení objednávky dojde pouze tehdy, pokud zadané údaje o platební kartě jsou platné, zákazník má dostatečnou hotovost na účtu a platba tedy projde."

Řekněme, že z těchto údajů vytvoříme (kromě dalších, zde nezmiňovaných) dva případy užití:

  1. UC001 - Založení objednávky zákazníkem
  2. UC002 - Platba kartou

Jaký vztah je podle UML mezi těmito případy užití ? Odpověď není tak jednoduchá, jak se může na první (a dokonce i druhý a ležérní třetí) pohled zdát... :-)



Tuesday, 18 April 2006 09:27:39 (Central Europe Standard Time, UTC+01:00)       
Comments [27]  Programátorské hádanky | UML


 Tuesday, 11 April 2006
Pár tipů na dobré blogy a typy blogů, které nemám rád

I když většinou žádné blogy neodporučuji, pomineme-li jako implicitní doporučení můj blogroll v pravé části stránky, a dokonce ani žádné nehaním, rozhodl jsem se při blížícím se dvouletém výročí mého vstupu do blogosféry :-) udělat výjimku.

Tip 1 - Borkův blogovníček - Borek píše spoty o počítačích, programování (PHP, .Net Framework), škole (VŠE) a zatím jsou sice jeho spoty sice spíše extenzivní než intenzivní, ale už teď je z nich patrné, že jejich autor není a a nebude žádný zoufalý "truhlík" bez názoru, jehož blog by byl archaickou manufakturou specializovanou na přeťukání zpráv z oficiálních médií nebo tupým seznamem linků z jiných blogů.

Tip 2 - Chorobovýplody - Blog Petra Lazeckého na serveru Vyvojar.cz sice není žádnou horkou novinkou, ale lidé vyvíjející na MS technologiich by jej měli číst povinně.  Články o C++/CLI nebo o "odvšivování" aplikací patří k tomu nejlepšímu, co se dá v Čechách o tématu nalézt,  a kvalitou svých spotů Petr několikanásobně převyšuje běžnou úroveň článků na vývojáři.

Tip 3 - GeoN - a něco ze zcela jiné oblasti. GeoNův blog je pro mě mimořádným "úkazem" na českém internetu. Nestává se často, aby si člověk s tak skvělým všeobecným vzděláním založil vlastní blog. GeoNův blog není pro každého a při jeho čtení se budete často rozčilovat, že autor občas vynáší apodiktické soudy, aniž by je pořádně zdůvodnil, nebo že laxně interpretuje pojem "pravda" a různými "oslími můstky" kritizuje pak i ostřelováním ze zálohy koncepci "metafyzické" a potažmo "vědecké" pravdy. Rozčilenost je alespoň u mě signálem, že se setkávám s textem, který mě nenechává lhostejným. GeoNa doporučuji - zapomeňte na hloupé a únavné přednášky o politologii nebo filosofii a nechte na sebe působit texty, kde myšlení "žije" a ne se jen konzervuje a zabíjí tupým  přemíláním nudných postulátů a exhumací myšlenek jiných, jak tomu mnohdy stále je hlavně na akademické půdě. Opakování totiž není matkou moudrosti, což se nám snaží vnutit  ty milé, labilní a intelektem většinou nevynikající paní učitelky ze ZŠ, ale jak věděl už Ladislav Klíma, opakování je jen matkou debility...

Určitě z blogu doporučuji alespoň dva články, které mě velmi zaujaly:

...Hierarchie parazitismu (až přízračně pravdivé postřehy o společnosti)
GeoNova volební kampaň 2006

A jaké typy blogů nemám rád? O jednom typu jsem se už zmínil. Patří do něj blogy, které mě vždy utvrdí ve víře v existenci dávicího reflexu. Jsou to blogy a články naplněné jen dalšími a dalšími únavnými seznamy odkazů, mezi které ti chytřejší alespoň občas hodí nějakou slovní vycpávku. Takových "blogů"  stále přibývá a já jsem nikdy nepochopil, proč jejich autoři sami sebe dobrovolněvystavují na moderním pranýři,  nad nímž je přibitý nápis "nic neumím, nic nedovedu, tak aspoň odkážu na ty ostatní". Moderní forma veřejného sebemrskačství... :-)

Dalším typem blogů, které se mi nelíbí, ale které mají asi velkou čtenářskou základnu, jsou blogy se spoty, které se skoro vždy "vezou" na nějakém "aktuálním" společenském tématu a které využívají laciných titulků k nějakému triviálnímu sdělení, jehož napsání muselo autorovi trvat asi 30s, do kterých můžeme započítat i spuštění počítače z hibernovaného stavu. Hlavním znakem blogu je za všech okolností názorová průměrnost - výhodou je, že když na blog přijdete třeba pro roce, nic vás nepřekvapí a vše je stále při starém a můžete si oddechnout, že starý dobrý středostavovský svět otce Kondelíka stále žije. Vyměnily se jen nepodstatné rekvizity, Knedlo Zelo Vepřo doplnila třeba Fabia nebo Roomster. :-) Typický zástupce - Laco stále bloguje.

U posledního blogu, který nemám rád,  jsem na vážkách. Myslím, že ani nejde o "typ" blogu, protože Letinka je unikátním a hýčkaným exemplářem na českém internetu a způsob jejího psaní nejde jednoduše převést na určitá pravidla, ani není snadné v něm najít nějakou šablonu nebo vyčpělou šmíru jako u předchozího typu blogu. Když jsem ale uvažoval, proč zrovna mě Letinka neoslovuje, musím říci, že nemám rád typ psaní, kde vládne cosi, co bych nazval "násilně předzjednanou harmonií". Její spoty se snaží být až příliš "tolerantní" a "moudré", nanejvýš pouč(e)né a "laskavé". Ale ta laskavost je přeslazená, takový Svěrák dovedený ad absurdum, a čiší z ní, tu více, tu méně,  že je jen speciálním a dovedně smíchaným destilátem připraveným pro vstřícně naladěné internetové publikum. Za čpící pachutí laskavosti tušíme nepřirozenou  a záměrně zvolenou stylizaci, která je neorganicky naroubována na osobnost, jež je mimo sféru internetu určitě citově i intelektuálně mnohem bohatší a zajímavější, než nám předvádí ve své zbytečné a občas i nevkusné internetové masce. Někdy mi přijde, že Letinka musí mít záměrně ve spotech "lehký žal", aby se jí nad obdivnými komentáři dojatých trumberů mohl rozlehnout v hrudi "hluboký smích" z emocionálně deprivovaného a šíleného světa, který si nakloníte na svou stranu jednou "cituplnou" či sentimentální větou. Kýč na druhou.:-)



Tuesday, 11 April 2006 11:52:19 (Central Europe Standard Time, UTC+01:00)       
Comments [12]  Ostatní


 Sunday, 09 April 2006
Bázová třída pro typové kolekce v .NET Frameworku 2.0

V souvislosti s uvedením generiky v .NET Frameworku se v různých článcích dočtete, jak generika usnadní vytváření a použití typových kolekcí. To je sice pravda, ale v článku se kromě zjednodušených příkladů a frikulínských hlášek o dokonalosti .NETu 2.0 z úst (respektiva pera) excitovaných jedinců po právě dokonaném intimním styku se softwarovou emanací božstva Microsoftu :-D málokdy dovíte, jak by taková typová kolekce měla vypadat v běžné aplikaci.

Proč nevyhovuje obyčejné použití generického typu List? (deklarace typové kolekce objednávek ve tvaru List<Order> orderCollection = new List<Order>()).

  • Jednou z dobrých praktik u generik je co nejvíce před uživateli (dalšími vývojáři) skrývat informaci, že pracují s generickým typem. Ač mně syntaxe pro práci s generickými typy připadá intuitivní, nemusí si to myslet všichni, a mnoho vývojářů stále asi raději používá důvěrně známý kód OrderCollection orderCollection = new OrderCollection() místo výše zmíněného kódu List<Order> orderCollection = new List<Order>()).  Tento požadavek by ale List<T> splnil  - typová kolekce může být potomkem List<T>.
  • Ve třídě List nejsou metody Add a Remove virtuální. To znamená, že nemůžete po přidání nebo odebrání položky z/do kolekce vyvolávat vlastní události. A to je problém, protože po přidání/odebrání položek z kolekce můžeme chtít nastavit/zrušit rodiče nebo přepočítát sumární hodnoty za položky v kolekci apod.

Bázová třída pro všechny kolekce, kterou používám, je otevřeným generickým typem a jejím předkem je třída Collection<T> z jmenného prostoru System.Collections.ObjectModel. Třída Collection<T> nabízí virtuální chráněné metody InsertItem a RemoveItem, ve kterých můžete vyvolávat potřebné události. Jestliže používate návrhový vzor Layer SuperType a máte tedy jednu bázovou třídu pro všechny business objekty (BusinessObjectBase), je vhodné, aby bázová třída pro kolekce kladla na generický typ T omezení, že musí být potomkem třídy BusinessObjectBase. Omezení slouží k tomu, abyste ve svých kolekcích mohli intuitivně používat všechny atributy a metody deklarované na úrovni společného předka BusinessObjectBase.

Kód kolekce:

   public class BusinessCollectionBase<T> : Collection<T> 
                                        where T : BusinessObjectBase
    {
        #region Events
        public event EventHandler<CollectionChangeEventArgs> ItemAdded;
        public event EventHandler<CollectionChangeEventArgs> ItemRemoved;
        #endregion Events
        #region Protected methods
        /// <summary>
        /// Přidání položky do kolekce
        /// </summary>
        /// <param name="index">Index položky</param>
        /// <param name="item">Vkládaná položka</param>
        protected override void InsertItem(int index, T item)
        {
            base.InsertItem(index, item);
            OnItemAdded(new CollectionChangeEventArgs(item));
        }

        /// <summary>
        /// Přidání položky do kolekce
        /// </summary>
        /// <param name="index">Index položky</param>        
        protected override void RemoveItem(int index)
        {
            T item = this[index];
            base.RemoveItem(index);
            OnItemRemoved(new CollectionChangeEventArgs(item));
        }

        /// <summary>
        /// Metoda odpovědná za vyvolání události ItemRemoved
        /// </summary>
        /// <param name="e">Argumenty události</param>
        protected void OnItemRemoved(CollectionChangeEventArgs e)
        {
            if (ItemRemoved != null)
            {
                ItemRemoved(this, e);
            }
            
        }
        
        /// <summary>
        /// Metoda odpovědná za vyvolání události ItemAdded
        /// </summary>
        /// <param name="e"></param>
        protected void OnItemAdded(CollectionChangeEventArgs e)
        {
            if (ItemAdded != null)
            {
                ItemAdded(this, e);
            }
         
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public virtual T FindById(Guid id)
        {
            List<T> mylist = (List<T>) Items;
            T objectMeetsCriteria = null;
            objectMeetsCriteria = mylist.Find(delegate(T iterObject)
                                  {
                                      if (iterObject.Id == id)
                                      {
                                          return true;
                                      }
                                      else
                                      {
                                          return false;
                                      }
                                                                
                                  });

            return objectMeetsCriteria;
        }

        /// <summary>
        /// Nalezení všech objektů splňujících zadanou podmínku
        /// </summary>
        /// <param name="criteria">Podmínka výběru</param>
        /// <returns>List s objekty, které splňují zadanou podmínku</returns
        public virtual List<T> Find(Predicate<T> criteria)
        {
            List<T> mylist = (List<T>) Items;           
            return (mylist.FindAll(criteria));
            
        }
        
        /// <summary>
        /// Spuštění akce nad všemi elementy v kolekci
        /// </summary>
        /// <param name="action">Akce, která se má provést</param>
        public virtual void ForEach(Action<T> action)
        {
            List<T> mylist = (List<T>)Items;
            mylist.ForEach(action);            
        }
    
        #endregion Protected methods
    }
}

Jak vidíme:

  1. Třída BusinessCollectionBase je potomkem třídy Collection<T> a vyžaduje, aby typ T byl vždy potomkem BusinessObjectBase. Motivace pro toto rozhodnutí jspu popsány výše.
  2. Nadeklarovali jsme dvě události ItemAdded a ItemRemoved, které jsou vyvolávany v přepsaných metodách InsertItem (ItemAdded) a RemoveItem (ItemRemoved). Pokud bych měl zájem, mohu jednoduše přidat i události vyvolávané před přidáním/odebráním položky z kolekce.
  3. Do rozhraní BusinessCollectionBase jsem také přidal několik zajímavých metod.
    1. Metoda FindById nalezne podle předaného Id (unikátní identifikátor instance) objekt v kolekci. V této metodě opět používáme nové konstrukce z .Net Frameworku 2.0. Implementační objekt kolekce (starý známý List<T> ) vystavuje metodu Find, která očekává generického delegáta Predicate z jmenného prostoru System.
      public delegate bool Predicate( T obj);
      Delegát Predicate je "ukazatelem" na metodu, která očekává jeden generický argument T a vrací true nebo false. Delegát Predicate tedy zastupuje metodu s podmínkou, která je pro předaný argument obj pravdivá nebo nepravdivá. My pro vytvoření podmínky použijeme anonymní metodu, která vrátí true pouze tehdy, když se Id objektu v kolekci shoduje s předaným Id. Atribut Id u generického typu T kolekce můžeme používat právě proto, že jsme zavedli pro typ T omezení (musíš být potomkem  BusinessObjectBase) a atribut Id je deklarován ve třídě BusinessOBjectBase.
    2. Pro pokročilejší operace s elementy kolekce jsme z objektu List<T> zveřejnili metody FindAll A ForEach. Metoda FindAll podle předané podmínky (delegát Predicate) nalezne a vrátí všechny objekty, které jí vyhovují. Metoda ForEach spustí pro všchny elementy v kolekci "akci - činnost" implementovanou v metodě, na níž "ukazuje" další užitečný delegát Action<T>.

      public delegate void Action<T> ( T obj);

      Když tedy budete chtít všechny objekty v kolekci zrušit, místo psaní cyklu foreach napíšete kód podobný tomuto:

      myCol.ForEach(delegate(OrderItem item)
      
                  {
      
                       item.Discard();
      
                  });
      

Vytváření vlastních typových kolekcí je jednoduché:

    /// <summary>
    /// Kolekce objektů OrderItem
    /// </summary>
    public class OrderItemCollection : BusinessCollectionBase<OrderItem>
    {

    }
 

Pro úplnost sem dávám triviální kód třídy pro argumenty události CollectionChanged.

    /// <summary>
    /// Objekt v kolekci
    /// </summary>
    public class CollectionChangeEventArgs : EventArgs
    {
        #region Private variables
        private BusinessObjectBase m_collectionObject;
        #endregion Private variables
        
        #region Constructors
        /// <summary>
        /// Konstruktor
        /// </summary>
        /// <param name="collectionObjekt">Objekt v kolekci, kterého se událost týká</param>
        public CollectionChangeEventArgs(BusinessObjectBase collectionObject)
        {
            BasicValidations.AssertNotNull(collectionObject, "collectionObject");
            m_collectionObject = collectionObject;
        }

        /// <summary>
        /// Objekt v kolekci, kterého se událost týká
        /// </summary>
        public BusinessObjectBase CollectionObject
        {
            get
            {
                return m_collectionObject;
            }
        }
        #endregion Constructors
    }
Související články:

Bázová třída pro business objekty - návrhový vzor Layer Supertype
Cachování řádků z databáze pro business objekty - třída DataCacheHelper
Ukázka použití třídy BusinessObjectBase



Sunday, 09 April 2006 14:34:33 (Central Europe Standard Time, UTC+01:00)       
Comments [7]  .NET Framework | Compact .Net Framework | Návrhové vzory