\


 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


 Tuesday, 28 March 2006
Další FAQ k .NET Remotingu
  1. Při použití CAO (Client Activated) objektu nebo při vrácení MarshalByRefObjectu ze SAO (Server Activated) objektu fungují volání metod jen v lokální síti. Na počítači přistupujícím přes internet (a komunikujícím tedy většinou přes adresu firewallu/routeru) volání metody vzdáleného CAO objektu vždy selže.

    Důvodem je, že každý CAO objekt je identifikován unikátním dynamickým URI, které je vygenerováno na serveru. Server za firewallem/routerem ale vrátí název počítače nebo IP adresu (v závislosti na nastavení vlastnosti useIpAddress u přenosového kanálu), které jsou platné pouze v lokální síti. Nastavením vlastnosti machineName u kanálu můžeme zadat, jaký název serveru (IP adresa) mají být v URI pro CAO objekty vráceny - zadáme tedy externí a pro klienty viditelnou adresu (např. adresu firewallu).

    V Konfiguračním souboru

    <channel ref="tcp" machineName="serverExternalVisibleName">
    </channel>

    V kódu:
    IDictionary properties = new Hashtable();
    properties["machineName"] = "serverExternalVisibleName";
    TcpChannel tcpChannel = new TcpChannel(properties, null, null);
    ChannelServices.RegisterChannel(tcpChannel);
  2. Při komunikaci se serverovým objektem dostanete hlášení, že selhalo přihlášení k proxy (The remote server returned an error: (407) Proxy Authentication Required).

    Net Remoting podporuje přihlášení k webovému serveru, ale jeho autoři trestuhodně a pravděpodobně omylem (ale i ve verzi 2.0?) nezveřejnili pro zadání přihlašovacích údajů objekt IWebProxy. Jediným nepříliš čistým řešením (pomineme-li nespolehlivé zadání autentizačních údajů přes třídu GlobalProxySelection) je použití reflection a nastavení privátního člena _proxyObject v objektu HttpClientChannel.

    //Vytvoření nového http komunikačního kanálu
    HttpChannel channel = new HttpChannel();
    
    //Získáme deskriptor člena _clientChannel (klientský http kanál) ve třídě HttpChannel
    FieldInfo clientChannelFO = typeof(HttpChannel).GetField("_clientChannel",   BindingFlags.Instance|BindingFlags.NonPublic);
    
    //Získání instance HttpClientChannel
    HttpClientChannel clientChannel = clientChannelFO.GetValue(channel);
    
    //Získání deskriptoru proxy objektu
    FieldInfo proxyObject = typeof(HttpClientChannel).GetField("_proxyObject", BindingFlags.Instance | BindingFlags.NonPublic);
    
    //Vytvoření nového proxy objektu
    IWebProxy authProxy = new WebProxy("proxy", 80); 
    
    //Pro autentizaci k proxy použijeme údaje přihlášeného uživatele
    authProxy.UseDefaultCredentials = true;
    
    //Nastavení nové proxy v objektu HttpClientChannel
    proxyObject.SetValue( clientChannel, proxy );
    

Starší FAQ k .NET Remotingu na tomto blogu

Dva nejčastější dotazy k .NET Remotingu
Dotazy a odpovědi k .NET Remotingu



Monday, 27 March 2006 23:47:11 (Central Europe Standard Time, UTC+01:00)       
Comments [0]  .NET Framework | .Net Remoting


 Sunday, 26 March 2006
UML - O agregaci, kompozici a asociaci a jako bonus společenská aktualitka :)

Na svých přednáškách při vysvětlování asociace a kompozice mám slide, na kterém jsou zmíněny základní rozdíly mezi oběma typy vztahů v UML. Ihned k tomu ale dodávám, že zmíněné rozdíly jsou akademické a že v praxi si vystačíme většinou s jedním typem vztahu (s agregací), u kterého při kódování intuitivně víme, zda složený (kompozitní) objekt rozhoduje, a pokud ano, tak v jaké míře, o životním cyklu svých konstituentů (objektů, z nichž je složen).

 

Kompozice
  • Kompozitní objekt nemůže existovat bez komponentních složek.
  • Každý komponentní objekt může být součástí jen jedné kompozice
  • Kompozice je většinou heterometrická
Agregace
  • Agregace může existovat bez svých konstitučních objektů
  • Jeden objekt může být potenciálně konstituentem více konstitučních objektů
  • Agregace inklinují k homeometrii

Informace o rozdílu mezi agregací a kompozicí vycházejí z UML specifikace, kde se říká:

"[Agregace je] speciální forma asociace, která specifikuje vztah mezi agregujícím(celkem) a jeho konstituentem (částí)."

"Kompozitní agregace je silnější forma agregace, která vyžaduje, že jakákoli instance konstituenta (části) bude součástí nejvýše jednoho kompozitního objektu. Jestliže je kompozitní objekt smazán, jsou většinou všechny jeho části vymazány s ním".

Čte někdo vůbec UML specifikaci namísto čtení takzvaně přístupných  a "lidsky psaných" knih, které dogmaticky vyžadují rozlišování mezi kompozici a agregací? Jak si můžete všimnout, v definicích agregace i kompozice je zřetelně vidět pozvolný přechod mezi asociací, agregací a kompozicí a ne žádné ostré hranice, jak se nám mnohdy snaží vsugerovat sekundární literatura k UML nebo žabomyší akademické války o přesný význam termínů. Převedu-li definice a jejich důsledky do normální řeči - agregace ani kompozice není z hlediska UML nic jiného než asociace. Protože se ale asociace s rysy kompozice a agregace vyskytují často,  zavedeme pro ně speciální jazykový konstrukty. Tyto jazykové konstrukty jsou implicitními nositeli omezení, jež jsou na agregaci a kompozici kladeny. Spory o to, co je v diagramu ještě agregace a co už musí být kompozice jsou směšné a nikam nevedoucí  - je to jen zvlášní druh moderního pseudovědeckého sektářství, kde se na hranici místo kacířů zástupně smaží nedogmatický duch UML.

Dále moje rozlišení agregace a kompozice vycházejí z praxe, kde indukcí dojdete k tomu, že kompozice bývá heterometrická  - konstituenti jsou objekty z různých tříd. Typicky například u faktury rozlišujete mezi řádky faktury, záhlavím faktury a zápatím faktury - faktura je tedy složena minimálně z objektů tří různých tříd. Když faktura nemá záhlaví, zápatí nebo alespoň jeden řádek, nemůže jít o fakturu. 

U agregace si častěji všimneme toho, že agregované objekty mohou být sdílené a že nezanikají se zánikem celku. Typicky o agregaci hovoříme třeba, když budeme modelovat kalendář pro obchodní zástupce a v kalendáři budou zadávány  jejich schůzky. Kalendář jako takový (seznam dní) může existovat i bez jakékoli evidované události. Některé události v kalendáři jsou privátní - typicky pravidelná návštěva přiděleného zákazníka. Jiné události jsou sdílené - společná schůzka všech obchodních zástupců je (přesněji řečeno - v tomto případě může být výhodně modelována jako) sdílená událost ve více kalendářích. I ty takzvaně privátní schůzky mohou "putovat" po kalendářích různých obchodních zástupců, když se dohodnou, že jeden po dobu dovolené zastoupí druhého a že převezme i jeho schůzky.

Důležité je si uvědomit, že v jazycích jako je C# nebo Java je rozdíl mezi kompozicí a agregaci opravdu zanedbatelný. Důvod je jednoduchý - nemáme v nich operátor delete([]) a odpovědnost za likvidaci objektů za nás převzal Garbage Collector. V C# a Javě si musíme pouze hlídat řízení životního cyklu objektů ukládaných do databáze - pokud něco (exkluzivně i sdíleně) vlastním (kompozice i agregace) , měl bych si uvědomit, že:

  1. Při zániku vazby musí dojít k odstranění objektu z databáze. Tedy odebere-li někdo řádek faktury z kolekce, je objekt faktura odpovědný za smazání vazby.
  2. Jestliže nemažu vazby fyzicky v databázi, ale pouze u objektů ze zrušených vazeb nastavuji stav 'neaktivní', musí moje business vrstva centrálně podporovat princip "co je neaktivní, je tabu a nikdo s tím nesmí pracovat  - a jak to v SW bývá, vždy máme výjimky. Jedinou výjimkou z tohoto pravidla jsou objekty, u nichž eviduji historii."

Poslední poznámka z praxe:

Na jedné přednášce (myslím před rokem na DNG) jsem se setkal s názorem, že typickým zástupcem agregace je "typování" objektů. Pod typováním objektu se můžeme představit objekt Uchazeč o práci, který má na sobě navázáno 0..n dalších objektů z třídy (z hlediska databáze z číselníku) Schopnost (řidičák, anglický jazyk, německý jazyk, práce s Excelem, lámání ženských srdcí atd.). Schopnost je zde termín, pod který jsou subsumovány všechny sledované typy evidovaných znalostí a dovedností. "Typování" není nic jiného, než klasifikace objektů dle různých kritérií, což nám umožňuje objekty rychle seskupovat do (z hlediska projektu) zajímavých množin - například budu-li obsazovat pozici lamačem srdcí se znalostí německého jazyka, snadno zjistím množinu uchazečů splňujících zadaná omezení.

Každý uchazeč může tedy "agregovat" o..n znalostí. Ale jde opravdu o agregaci? Já myslím, že je to prostá asociace - uchazeč nemá žádnou zvláštní vazbu na znalosti, ty jsou k němu jen "volně přidruženy".

A za jakých podmínek by bylo vhodné překvalifikovat vazbu mezi Uchazečem a Schopností opravdu na agregaci ? V momentě, kdy budete chtít evidovat nějakou dodatečnou a unikátní informaci k vazbě mezi uchazečem a jeho schopnostmi. Když tedy budeme chtít zjistit, od kdy uchazeč vlastní řidičský průkaz, nebo kolik dobytí ženských srdcí posloužilo jako předmostí k dobytí klínů;-) , zavedeme novou třídu DetailSchopnostíUchazeče - tato třída bude v asociaci s původní třídou Schopnost a bude agregována třídou Uchazeč (anebo dokonce v tomto případě bude jejím komponentním objektem) :-) .

Proč? Informace, které nesou objekty z třídy DetailSchopnostíUchazeče nemají význam "an sich", ale jen ve spojení s uchazečem. Jsou nedílnou částí právě jednoho obrazu, který nám dává objekt Uchazeč. Třída Schopnost nedílnou součástí obrazu právě jednoho Uchazeče nebyla - nenesla žádné specifické informace o uchazeči, jen s ním byla svázána náhodným poutem - asociací.

Na konec aktualitka na asociaci a kompozici ze života. :)

Asociace je pouhé registrované partnerství, ve kterém jsou dva konstituenti nahodilými objekty, kteří mají vůči sobě jeden kontingentní a zparchantělým parlamentem posvěcený link. Oba nijak závazně neřídí životní cyklus toho druhého.

Uzavřením manželství vzniká sakrální kompozitní objekt, jehož nedílnými součástmi jsou oba manželé s vzájemně protknutými životními cykly. A jak víme, při zániku kompozitního objektu, dříve či později nevratně odumírají i komponentní objekty.

I když nemusíme rozlišovat mezi asociací, agregací a kompozicí v UML, v životě může být dobře patrný rozdíl mezi asociací a kompozicí diferencujícím znakem mezi frivolní hrou a závazným svazkem. A pak že nelze do odborného blogu jednoduše a nenásilně propašovat názor na politická nebo společenská témata:-)



Sunday, 26 March 2006 15:50:53 (Central Europe Standard Time, UTC+01:00)       
Comments [5]  UML


 Sunday, 05 March 2006
Termíny kurzů o OOP a UML, partnerství s EIITE, InHouse školení

UPDATE:

Podrobné a aktuální informace o dalších termínech školení a nabídce dalších služeb naleznete nyní zde.


 

Jak jsem již naznačil v předchozím spotu, uzavřel jsem "strategické partnerství" s novým školícím střediskem - se společností EIITE. Mé kurzy budou pořádány pod hlavičkou Skilldrive.

Všechny kurzy se budou konat v Praze.

Přesná adresa:

EIITE Praha
Karlovo nám. 17
120 00 Praha 2

 

Termíny kurzů:

  • Objektovými principy a návrhovými vzory řízený design a vývoj kvalitních aplikací - 3-5.5 2006 (každý den od 9:00 do 16:00). Program a další informace o kurzu naleznete v předchozím spotu. Přihlášky na kurz je možné stále posílat na adresu petra@renestein.net.
    Kurz je obsazen: Pokud máte stále  zájem o kurz, napište nám prosím opět na adresu petra@renestein.net a my Vás budeme informovat ihned po vyhlášení  dalšího termínu školení. Je také možné stále objednávat InHouse školení (viz níže).
  • Kurz UML pořádaný a administrativně zajišťovaný společností EIITE - 28-29.8. 2006. Přihlášení na kurz.

InHouse školení

Pokud máte zájem o inhouse školení zaměřené na OOP, návrhové vzory, UML, .NET Framework, Compact .Net Framework nebo chcete vytvořit kompletní systémový design aplikace včetně naprogramování klíčových částí, napiště prosím svůj požadavek také na adresu petra@renestein.net nebo nás kontaktujte na telefonním čísle +420 603 266 732. Omezení pro inhouse školení, o kterých jsem zde psal dříve, již neplatí!



Sunday, 05 March 2006 12:36:23 (Central Europe Standard Time, UTC+01:00)       
Comments [0]  Kurzy UML a OOP | Návrhové vzory | UML


 Sunday, 26 February 2006
Několik informací ke kurzům UML a OOP

Takže předběžně ke kurzům UML a OOP, protože se mi nechce psát stále stejné věci každému zvlášť do mailu. V souvislosti se změnou zaměstnání se mění i některé věci ke kurzům.

  1. Kurzy OOP a UML již nebudou pořádány ve školícím středisku DIGI TRADE, ale ve velmi pěkných prostorách jiné společnosti, s níž jsem uzavřel "strategické partnerství" a jejíž jméno oznámím příští týden.
  2. První termín (pravděpodobně konec dubna/začátek května) patří kurzu Objektovými principy a návrhovými vzory řízený design a vývoj kvalitních aplikací., na kterém již mnozí z vás byli. Pro připomenutí níže vkládám program kurzu. Pokud máte již nyní zájem předběžně si zarezervovat místo na kurzu, pošlete prosím email na adresu petra@renestein.net. Cena kurzu je 13 000 Kč.
  3. Dále cca za měsíc zveřejním podrobný program a termín dalšího mého školení s pracovním podtitulem "Design aplikací a návrhové vzory prakticky  - od chaosu k řádu".
  4. S novým školícím střediskem budeme také pořádat "jednodušší" (přesněji řečeno jinak zaměřený a více na základní znalosti orientovaný) kurz, uvádějící posluchače prakticky do světa UML (2.0). Podrobnosti a termín zveřejním do 14 dnů.
  5. Fungovat to bude takto - první dva kurzy je po administrativní stránce zcela na mě, kurz o UML bude po admistrativní stránce plně zajišťovat nové školící středisko. I program kurzu o UML jsem samozřejmě připravil i já, nikdy bych nemohl školit nějaké "předžvýkané" řečičky někoho jiného. Uvádím to zde jen proto, aby vás nemátlo, když se u některých kurzů objeví informace, že máte přihlášky posílat mně (respektive mé ženě) a u jiných budete přihlášky směřovat rovnou na nové školící středisko. Kurzy se ale budou vždy konat na stejném místě.
  6. Omlouvám se těm, kdo absolvovali první kurz a čekají na již poměrně dlouho slibované uvolnění studijních materiálů. Prozatím jsem nenašel čas (respektive vždy jsem našel zajímavější práci ;) , než je "vyčištění" materiálů k veřejnému použití) a také se mi nechce kvůli špatným zkušenostem uvolňovat materiály před konáním dalších kurzů, protože jsem se už v reálu setkal s tím, jak materiály neurčené široké veřejnosti začnou po internetu rychle kolovat, po čemž opravdu nijak netoužím. :(

1. den

  1. Přivítání účastníků kurzu.
  2. Úvodní informace o zaměření a organizaci kurzu.
  3. Základní pojmy OOP a UML..
  4. Mýty o OOP a UML.
  5. Vysvětlení rozdílů mezi business analýzou, systémovým designem a implementací aplikace na konkrétní platformě.
    1. Světlo v temnotách – Model Driven Architecture (MDA)
  6. Základní architektura a rozvrstvení aplikace.
  7. Statický pohled na systém – vytváříme základní diagram tříd a ověřujeme, že jsou v něm zaneseny všechny informace, jež jsou nám známy z případů užití.
    1. Zvolení složitosti diagramu tříd. Potřebujeme vždy flexibilní doménový model?
    2. Zapouzdření objektů, polymorfismus, návrh metod.

                                                               i.      Důležitost principů kovariance a kontravariance.

                                                             ii.      Různé typy soudržnosti metod.

                                                            iii.      Rozhodnutí o typu viditelnosti u každého člena třídy.

                                                           iv.      Jaké konstruktory by měl nabízet každý objekt z problémové domény? Jak určit vlastnosti pouze pro čtení.

                                                             v.      Ověření bezpečného chování třídy vůči potenciálním klientům.

    1. Precizní definice vztahů mezi třídami. Asociace, kompozice, agregace, závislost, realizace, generalizace.
    2. Vysvětlení rozdílů mezi abstraktní třídou a rozhraním (interface).

                                                               i.      Vztah mezi typem a podtypem.

                                                             ii.      Rozpoznání primárního účelu (hlavního smyslu) třídy i jejich sekundárních odpovědností vynucených vztahy s objekty z různých vrstev.

  1. Praktický příklad - ukázka implementace vzorových vztahů mezi objekty, perzistence objektů z problémové domény a zobrazování dat.  (jazyk C#)
    1. Separace kódu pro ukládání a obnovení objektů z perzistentního úložiště v samostatné vrstvě.
    2. Jak zajistíme, že v paměti počítače existuje nanejvýš jedna instance objektu se stejnou identitou.
    3. Ukázky různých způsobů mapování agregace, kompozice, generalizace a asociace do databáze.
    4. Zajištění existence maximálně jedné instance objektu v systému.
    5. Efektivní ukládání a nahrávání kolekcí.
    6. Jak se slučuje objektový přístup a přímé použití DataSetu (recordsetu) v uživatelském rozhraní?
  2. Odpovědi na dotazy frekventantů kurzu.

2. den

  1. Vysvětlení pojmu návrhový vzor.
  2. Kdy byste měli používat návrhové vzory?
  3. Základní vzory (GoF vzory)
    1. Vzory pro řízení vzniku objektů.
    2. Strukturální vzory.
    3. Vzory pro chování objektů.
  4. Začlenění návrhového vzoru do designu aplikace. Kreativní aplikace vzorů.
  5. Kompozice vzorů do vyšších sémantických celků.
  6. Příklady odvozených návrhových vzorů často používaných při designu informačního systému.
  7. Kdy byste neměli používat návrhové vzory?
  8. Příklad - ukázky implementace složitějších vzorů. (jazyk C#).
  9. Odpovědi na dotazy frekventantů kurzu.

3. den

  1. Typické problémy při modelování informačního systému a jejich řešení.
  2. Modelování  složitých organizačních struktur.
  3. Výhody vytváření fasád (Facade) pro aplikace s více než jedním typem uživatelského rozhraní (lehký klient, těžký klient).
  4. Evidence kompletní historie objektu.
  5. Aplikační role a práva uživatelů.
  6. Vytvoření flexibilního systému, jehož chování je změněno bez rekompilace aplikace.
  7. Příklad – ukázky řešení problémů při modelování informačního systému. (jazyk C#).
  8. Odpovědi na dotazy frekventantů kurzu.
  9. Ukončení kurzu.


Sunday, 26 February 2006 20:27:49 (Central Europe Standard Time, UTC+01:00)       
Comments [0]  Kurzy UML a OOP | Návrhové vzory | UML


Analyticko-programátorská hádanka (vztahy mezi třídami)
Hádanka

Máte následující jednoduchý diagram tříd. Je na něm něco "podivného"? Abyste to neměli tak jednoduché, tak řeknu, že diagram je součástí přednášek Ing. Kamila Svobody, který na univerzitě v Hradci Králové vyučuje objektové modelování. Takže se vás třeba jen snažím zmást a ukázat, jak diagram precizně zpracovává své téma ;-) Anebo opravdu najdete nějaké nelogičnosti, na které by měl být kolega Svoboda upozorněn? ;-)

diagram tříd

Sunday, 26 February 2006 17:21:19 (Central Europe Standard Time, UTC+01:00)       
Comments [38]  Programátorské hádanky


 Saturday, 18 February 2006
O směšnosti jednoho z přežívajících mýtů o Microsoftu
mýty

Na úvod jedna terminologická poznámka. Myslím, že Lion Feuchtwanger říkal, že mýtus je na rozdíl od historie nejen to, co nikdy nebylo, ale kupodivu i to, co v současnosti stále je.

Když mluvím o mýtech kolem Microsoftu, mám tím na mysli všeobecně rozšířená přesvědčení a předsudky, které se donekonečna uměle vyživují zveličováním a zkreslením některých nešťastných přehmatů a chyb Microsoftu v minulosti. Chyby ale byly dodatečně exkulpovány razantní marketingovou kanonádou, takže se nestaly pro Microsoft tím osudovým klopýtnutím, o něž všichni jeho konkurenti pochopitelně tak stáli. O tom, proč takové marketingové kanonády nebyli schopni samotní konkurenti, když se bili v prsa, jak dobré produkty mají, psát nechci - snad jen podotknu, že rychlé pronikání Microsoftu do různých oblastí softwaru a spotřební elektroniky je někdy docela ukázkovým příběhem o neschopnosti a rigiditě řízení ostatních firem, kdy se lze jen dohadovat, proč v nich nedošlo ke stínání hlav neschopného managementu ihned při náznaku razantního poklesu tržního podílu dříve dominující společnosti zcela ve prospěch Microsoftu.  Kdyby se psaly dějiny neschopnosti, měl by v nich mít čestné místo management Palm platformy - přeci jen cpát lidem, že méně (funkcí) je více (funkcí), je přinejmenším neomaleně drzé a nové Treo s Windows Mobile je potupnou kapitulací dokazující, že nelze donekonečna primitivnost svého OS vydávat za úžasný klad. I marketing má své hranice - Q.E.D. ;-)

Takže jeden z mýtů o Microsoftu - Microsoft nemá kvalitní produkty, nabízí jen omalovánky (barvičky, klikátka, vějičky na BFU, průvodce, sponky - dosaďte dle libosti), ale jeho marketing dokáže v lidech vzbudit iluzi, že je to lepší než naše úžasné <dosaďte dle libosti>. Neříkám, že Microsoft má vždy nejlepší produkty ve všech oblastech, nebo že jeho marketing nepodává při podpoře prodeje produktů skvělé výkony - skvělé z hlediska prodejních výsledků, mě osobně toto pojetí marketingu nijak neoslovuje. Ani ale není pravda, že produkty Microsoftu prodává jen marketing, protože produkty kvalitativně stejné nebo lepší než konkurence nemá, a proto je nucen podlézat hloupé a tupé mase uživatelů nějakými líbivými grafickými pozlátky.

Podezřívavý a apriori zaujatý člověk se teď určitě ptá, proč vlastně tohle píšu? Třeba za nějaký mrzký jidášský peníz z marketingového budgetu Microsoftu. Konspirace musí být, já vím, a všichni rozumní přece vědí, kdo je dneska ďábel. ;-) Hlavní myšlenka tohoto spotu mě napadla při používání Nokie N90 (OS Symbian - Series 60)  - zvláště při přímém srovnání s platformou Windows Mobile, za jejíž zástupce a přímé konkurenty Nokie N90 můžeme považovat QTEK 8310 nebo i MDA Vario (Pocket PC Phone Edition).

Jak na mě zapůsobila Nokia.

Nečekal jsem od ní nic jiného, než to co jsem vyžadoval od dřívější 6230 - to znamená hlavně schopnost telefonovat a připojit se na internet. Neměl jsem žádnou potřebu na ni instalovat další programy, protože jako komunikátor mi slouží MDA Vario. Jaké však bylo moje překvapení, když jsem zjistil, že Nokia je nechutně pomalá třeba při přístupu do menu - toleroval bych zpožděný přístup při prvním otevření menu, ale menu se vykresluje při dalším otevření jen o malinko rychleji než při prvním přístupu. Dobře, zvyknout se dá skoro na vše. Skoro - již třetí týden musím pravidelně asi tak po sedmi dnech Nokii resetovat, protože se systém začne chovat velmi velmi podivně. Vstoupíte do menu, vyberete nějakou položku... a nic - jen zůstanete viset v menu a nic se nestane - žádná chybová hláška. Milostivě vám Nokia dovolí návrat do pohotovostního displeje a to je vše - pak proveďte reset, jestli chcete pracovat dále. A jen připomínám - Nokia je zcela holá, žádné programy jsem neinstaloval! Nokia PC Data Suite je slušný program, který konečně dokáže dobře nadetekovat telefon i synchronizovat data mezi telefonem a počítačem - nechápu ale vyžadování verze 1.4 nebo vyšší Widcomm ovladačů. Na svém domácím počítači s MSI USB BT klíčem jsem měl nižší verzi Widcommu, přes kterou se už připojilo bez reptání dost telefonů, ale teď jsem musel podstoupit upgrade, který nebude pro většinu "masových" uživatelů zase tak bezbolestný. Navíc připojení s Nokií přes GPRS/EDGE nepravidelně padá  - je to zcela evidentně chyba Nokie, protože ve stejnou dobu se stejným operátorem připojení přes Vario drží. Na čem si Nokia dala záležet jsou blbinky jako grafické motivy, hned v prohlížeči  telefonu máte záložku, abyste si mohli nahrát nové hry, no a hlavní je přece displej s vysokým rozlišením a úúúžasným počtem barev. Co na tom, že displej telefonu je docela malý při jeho porovnání s trochu zbytečně přerostlými rozměry telefonu. No a ten foťák, to je teprve radost pro pokročilé uživatele - ty mazanice s puncem Carla Zeisse jsou asi opravdu jedny z nejlepších v současných mobilních telefonech, jak se dočtete ve většině recenzí. V praxí to znamená pouze to, že místo rozmazané šmouhy vidíte občas docela dobře zaostřenou šmouhu.

Co tím chci říct - Nokia vyrobila telefon, který hýří různými multimediálními pozlátky a dokonce se pyšní podporou 3G sítí. Jenže místo dobrého nástroje dostanete nedotažený polotovar s operačním systémem, který mě o svých kvalitách nepřesvědčil. Celá N90 je drahé pozlátko bez pořádného obsahu a s operačním systémem, který je potřeba pořád restartovat. Marketing ale dokáže produkt na trhu dobře etablovat - nepřipomíná vám to něco? ;-)

Microsoft s platformou Windows Mobile jako by ani nebyl tím profláknutým Microsoftem. kterého všichni znají. Místo operačního systému hýřícího grafickými prostředky nabízí (v základním nastavení!) strohou, ale dobře funkční  obrazovku Dnes, fádní tlačítko Start a obyčejné zástupce nainstalovaných programů. Ne že by jeho OS (respektive samotná zařízení) netrpěl problémy - sám jsem se natrápil s rozchozením synchronizace s novým ActiveSyncem 4.1, ale i když si na Vario s "pomalým" Omap procesorem nainstalujete další aplikace, systém běží, nijak drasticky se nezpomaluje, navíc mi oproti Nokii nabídne připojení přes Wi-Fi. Jen ten foťák na Carla Zeisse nemá, nabídne mi jen staré známé šmouhy vhodné pro MMS. A ještě ke všemu člověk dostane od Microsoftu jen nějaké trapné a graficky chudé hry - skandál.  Vario nebo Qtek 8310  a další zařízení jsou jen takový nudný pracovní nástroj, který sice má své chyby, ale nijak zásadní a určitě ne neodstranitelné. V základní konfiguraci nudný pracovní nástroj - nic více. Na podbízivý a pestrobarevnými fanglemi hýřící Microsoft chabá vizitka. Dokonce se těm uživatelům málo vtírá, protože některá nastavení má umístěna z hlediska běžného uživatele na nečekaných místech - empiricky ověřeno. ;) A co je docela šokantní - do Pocket Wordu nebyl přenesen pan Sponka.

Takže ten mýtus, jak Microsoft prodává nefunkční software v bombastickém pozlátku, nějak nefunguje. Na předražené fangle a líbivá pozlátka zakrývající, že král je nahý,  je tady spíš Nokia. Na marketingový "imageový" balast je tu zase Nokia. Proč jen ten Microsoft nefunguje podle mýtotvorců? Divné, opravdu divné, vždyť ten mýtus je tak působivý - a co záleží na tom, že je lživý?

Mimochodem, ty takzvané srovnávací testy Symbianu a Windows Mobile "populárních" serverů a časopisů o mobilech, které vždy končí zcela "šokujícím" a dokola od sebe opisovaným tvrzením, že Windows Mobile jsou pro práci a Symbian pro zábavu, nemají oporu v realitě. Na Windows Mobile i Symbian existuje dostatek programů i her, které vám umožní udělat z jednoho i druhého zařízení buď multimediální výstřelek, nebo pracanta, anebo kupodivu dokonce obojí. Hlavní otázka je jiná. Jak vám pracant nebo multimediální nástroj bude ze zvolenou SW výbavou sloužit? A tomu se většinou v testech redaktoři vyhnou, protože by to znamenalo přejít od obecných plků k pořádnému testování.

Pár poznámek (i několik osobních) na závěr:

  1. Platforma Windows Mobile 5 není dokonalá. Microsoft dělá některé pro mě nepochopitelné kroky - Smartphone specifikace neobsahuje Pocket Word ani Pocket Excel, k dispozici máte jen prohlížeče office formátů. Absence Compact .Net Frameworku 2.0 v prvních verzích ROM s Windows Mobile 5 kvůli neexistujícímu načasování dokončení platformy Windows Mobile 5.0 s dokončením Compact .Net Frameworku 2.0 je neodpustitelná. Dlouhé čekání na uvedeni "push" emailu jako konkurenta BlackBerry  také nesvědčí o nějakém silném tahu na bránu. Kupodivu to ale na konkurenty (viz Palm) s přehledem stačí. O specifikaci SmartPhone 2002 nebo 2003 nemluvě - ze strany Microsoftu šlo spíš o první nástřely a rekognoskaci trhu s mobily, než že by byl schopen uvést se svými partnery na trh nějaká "killer" zařízení.
  2. Asi před rokem jsem při nějakém povídání s příznivcem Symbianu v nadsázce řekl, že má-li nějaké akcie Symbianu, měl by začít hledat vhodný okamžik, kdy je prodá. Nedávno ale i Gartner vydal studii, ve které  přestává Nokii a jejímu protežování Symbianu věřit. Navíc Nokia zakoupila licenci k ActiveSyncu ;)
  3. Tento článek není zamýšlen jako výzva k zuřivému flamu, ve kterém začnete vypočítávat, co všechno Nokia nebo Microsoft dělají špatně,  a pak přejdete plynule k urážkám oponentů. Takového flamu si do sytosti užijete na MobilManii, takže se na ni místo osočování se tady v komentářích raději rovnou přesuňte. Jsem příznivcem Windows Mobile, ale nejsem žádný nemilosrdný nepřítel Nokie. Používal jsem a používám různé telefony - od Nokie, Siemense, Sony Ericssonu po Philips atd. a nemám předsudky vůči žádnému ovládání ani platformě a smyslem článku není podat "totální" důkaz, co je lepší.
  4. Je o mně známo a nijak to nezastírám, že jsem Microsoft MVP, takže mě můžete "lacino" nařknout ze zaujatosti a z protežování jedné společnosti. Proti tomu se nelze bránit. Kdo mě zná, ví, že názorovou loajalitu k jedné firmě, produktu, světonázoru nebo bůhvíčemu dalšímu si u mě nelze prosadit.

 



Saturday, 18 February 2006 21:37:18 (Central Europe Standard Time, UTC+01:00)       
Comments [15]  Mobilitky | Ostatní


 Tuesday, 14 February 2006
Svatý Valentin - aneb o přitažlivosti kýče
srdce

Posledních pět let vždy o Svatém Valentinu slavím výročí uvědomění (no alespoň tedy to moje) si kapitulace běžné mužské racionality před ženskou kapriciozností. A v poslední době to dokonce už ani nebolí,  s moji malou prohru se asi dokázala vyrovnat i moje ješitnost. Když jsem se svou budoucí ženou teprve začínal "chodit"¨, tak jsme kromě zjišťování jiných příjemnějších rozdílů mezi oběma pohlavími in concreto vzájemně "ladili" a vyjasňovali si své názory na různé záležitosti. Samozřejmě v lednu a tedy v dostatečném předstihu došlo i na svátek Svatého Valentina. Použil jsem veškerou svoji výmluvnost, abych z mého pohledu brilantně a nevyvratitelně a s použitím jen velmi decentní psychologické manipulace zdůvodnil zbytečnost takového svátku:

  1. Co má tento narychlo importovaný svátek kdoví odkud společného s námi? (pokud by něco takového v Petře bylo, snažil jsem se, aby její nacionalisticko-izolacionistické smýšlení neškodně udeřilo v souladu s mými intencemi přímo na globální solar plexus McDonaldizovaného svátku :-D).
  2. Nebudeme přece slavit něco takového se všemi zamilovanými, zase nějaká stádní akce tentokrát "jen" pro všechny zamilované, ale přeci si nevyhradíme na lásku jeden den v roce a nebudeme jak nějací akurátní škrobení úředníci ze zamilovanosti dělat pravidelnou ordinérní položku v diáři (rafinovaný apel na respektování výjimečnosti každého a hlavně našeho vztahu).
  3. K dobru jsem dal i svou soukromou teorii, že svátek 14. února stanovil nejdříve nějaký velký obchodní řetězec, který potřeboval eliminovat pravidelný výrazný propad v tržbách mezi vánočními a velikonočními žněmi. Všechny obchodní řetězce tento trik další rok adoptovaly a poté jejich marketingová mašinérie ve svém momentálně vítězném a ryčném dějinném pochodu přesvědčila takzvané zamilované, že nejlepší co mohou v únoru dělat, je vyhazovat peníze za různé cetky. (Fikaná dehonestace svátku jeho přímou vazbou na "špinavé" obchody).
  4. Kdyby nic nezabralo, snazil jsem se v Petře rozehrát antikatolickou strunu - co já, mě by ten svátek vadit nemusel, ale víš sama, jak lhostejná jsi k církevnímu provozu a pověsti o svatých považuješ jen za bizarní smyšlenky z prehistorických dob, kdy bylo "in" nechat se sežrat  v aréně lvy nebo si nechat setnout hlavu pro přesvědčení, u nějž dokážes vnímat jen jeho absurditu. Navíc Svatý Valentin je podivný světec, o němž toho není moc známo a který navíc nebyl dlouho zařazen ani do celocírkevního liturgického kalendáře a teprve teď na něj ta horší podbízivá část církve nabaluje nečekaná moudra - třeba že nesl pochodeň lásky (tady se mi vždy vybaví navíc slovo lampion a odplivnu si, asi deformace z dětství) ve špatných časech a je důkazem toho, že láska je silnější než nenávist, blablabla.

A jak se moje argumenty ujaly? Petra se jejich údernosti ani nijak nevzpírala, dokonce se mi zdálo, že se mnou v mnoha konkluzích souhlasí. Byl jsem spokojen, jak brilantně se mi daří formovat další osobu k obrazu svému. ;)

Když jsem 14. února inkriminovaného roku dorazil domů, přišla mi Petra otevřít v načančaných šatech, které běžně doma nenosí (útok na smysly), po stěnách byly rozvěseny barevné balónky (slušný kýč) a dostal jsem nějaké přáníčko a dárky.

No a další rok i ty všechny následující jsem Valentínku a nějaké dárky začal kupovat i já. Žádnou zvláštní pointu nečekejte - já jsem jen zjistil, že mnohem raději mám lidi, co se mi nepodřizují, protože jsou zajímavější a není s nimi nuda, a že i excelentní kýč může být docela příjemným zpestřením života. ;) A na závěr jsem samozřejmě provedl jednu očistnou falešnou racionalizaci, kterou jsem z ješitnosti prostě vytvořit musel -  pořád lepší slavit svátek Svatého Valentina, u nějž nám alespoň legendy poskytují snesitelnou zástěrku pro tato sladkobolná pnutí, než 1. Máje na chudáka Máchu kydat tuny lyrického kýče, když on sám měl ve své tvorbě slabost pro titánská byronská gesta, než že by si potrpěl na rozněžnělá tokání mladých samečků a samiček a ve svých denících navíc dokázal, že by byl výborným studijním materiálem i se svou Lori pro teorie jistého doktora Freuda, protože v nich popisuje sex bez jakékoli "romantické" omáčky a zbytečných rituálních mileneckých tanečků.

Tohle vše ale neznamená, že bych skousl svátek zamilovaných v libovolném dni v roce a pod každou záminkou - až bude přicházet království velkokýče, poznáme to neklamně třeba podle toho, že budeme slavit svátek zamilovaných ve výroční den stvoření dvouhlavé saně vystupující pod uměleckým pseudonymem Bratři Nedvědi aka "na dlani jednu z tvých řas". A takového dne bych se dožít nechtěl ;-)

Tak to vše jen na okraj, aby v blogu nebyly jen spoty o navigaci, PDA a analýze, když si i tyto drobné zálety mohu dovolit, protože blog je výsostně soukromý žánr, moji milí čtenáři :-)



Tuesday, 14 February 2006 21:29:17 (Central Europe Standard Time, UTC+01:00)       
Comments [2]  Ostatní


 Tuesday, 07 February 2006
Malá utilitka pro navigaci TomTom
TomTom

Podnět k vytvoření tohoto malého prográmku vyšel z jedné diskuze na ce4you od MilanaSu. K čemu prográmek slouží? TomTom má výrobcem dodávané (ne uživatelem vytvořené) body zájmu uloženy v souboru POI.dat - poměrně snadno můžete vlastní body zájmu, které je možné pro Čechy stáhnout ze skvělého webu www.poi.cz, zkompilovat do vlastního souboru POI.dat. Když ale jedete do ciziny, většinou chcete TomToma spouštět s výrobcem dodaným souborem POI.dat, a ne se svým vlastním, který se hodí jen pro Čechy.

Přejmenování souborů a spuštění TomToma řeší utilitka RenameFile.exe, která by se mohla hodit i ostatním. Popis , jak utilitku používat,  zkopíruji z ce4you, abych jej nemusel psát znovu.

Psáno zcela záměrně bez diakritiky ;)

"
1) Vytvorte zastupce na Pocket PC (treba Total Commanderem nebo File Explorerem)

2) Zastupce zkopirujte do PC (pro lepsi editaci) a vytvorte
17#"\RenameFile.exe" "STORAGE CARD\DE_AT_CH_PL_CZ_PLUS-MAP\POI2.dat" "STORAGE CARD\DE_AT_CH_PL_CZ_PLUS-MAP\POI.dat" "STORAGE CARD\DE_AT_CH_PL_CZ_PLUS-MAP\POI3.dat" "Program Files\Navigator\TomTom navigator.exe"

1. argument - 17#"\RenameFile.exe" cislicka a cestu k programu (vse se muze lisit) ponechte beze zmeny.

2. argument "STORAGE CARD\DE_AT_CH_PL_CZ_PLUS-MAP\POI2.dat" - soubor, ktery ma byt prejmenovan tak, jak urcuje treti argument (POI.DAT)

3. argument - "STORAGE CARD\DE_AT_CH_PL_CZ_PLUS-MAP\POI.dat" - soubor ve 2. argumentu bude prejmenovan na soubor v tomto argumentu.

4. argument - "STORAGE CARD\DE_AT_CH_PL_CZ_PLUS-MAP\POI3.dat" - jak se bude nove jmenovat puvodni soubor (v nasem pripade POI.DAT - 3.argument).

5. argument - "Program Files\Navigator\TomTom navigator.exe"
Program, ktery ma byt spusten (TomTom).


Je potreba spravne napsat uvozovky a cesty - programek nema zadne UI. Vytvoreneho zastupce zkopirujte zpet do Pocket PC.

Program pracuje takto:

1) Jestlize neexistuje soubor v argumentu 2 (to znamena, ze POI.dat predstavuje pozadovany soubor), je spusten program v argumentu 5.

Jinak

2) Soubor v argumentu 3 je prejmenovan na soubor v argumentu 4 A
soubor v argumentu 2 je prejmenovan na soubor urceny argumentem 3 A Je spusten program v argumentu 5."

Použito jen "čisté" C++ a WIN API, takze by vám prográmek měl fungovat na všech verzích Windows Mobile.


 



Tuesday, 07 February 2006 23:58:54 (Central Europe Standard Time, UTC+01:00)       
Comments [0]  Mobilitky | Navigace


 Sunday, 05 February 2006
Ukázka použití třídy BusinessObjectBase

Máme-li napsanou třídu BusinessObjectBase, která hraje roli společného předka všech objektů v business vrstvě všech našich aplikací, je čas ukázat, jak vypadají typičtí potomci.



Předchozí spoty

Bázová třída pro business objekty - návrhový vzor Layer Supertype
Cachování řádků z databáze pro business objekty - třída DataCacheHelper

Zobrazit kód

Třída Order reprezentuje v našem systému objednávku. U objednávky nás zajímá, jakému patří zákazníkovi (vlastnost Customer), rozhodli jsme se, že budeme vyžadovat u každé instance objednávky popisek (vlastnost Description) a samořejmě samotná objednávka je složena z položek objednávky (kolekce Items). Položkou objednávky budeme rozumět třídu, v níž je uloženo, jaké zboží a kolik kusů si zákazník objednal a celková cena položky (kusová cena objednaného zboží * počet). Celková cena objednávky je sumou cen jednotlivých položek. Pro jednoduchost vidíte v kódu zatím jen třídu Objednávka.

  1. Třída Objednávka má dva konstruktory. Prvni konstruktor, přijímající popisek objednávky a zákazníka, vyvolává bezparamerický konstruktor třídy BusinessObjectBase. Jak jsem psal v předchozím spotu, bezparametrický konstruktor slouží k sestrojení objektů bez obrazu v databázi. Chcete-li založit novou objednávku, stačí když si uložíte odkazy na objekty předané v konstruktoru a zbytek práce delegujete na BusinessObjectBase, která nastaví všechny potřebné příznaky nutné pro práci s objektem bez perzistence. Druhý konstruktor přijímá Id (unikátní identifikátor) objednávky, která je uložena v databázi. Jeho tělo je prázdné, veškerou činnost provádí BusinessObjectBase - nastavení příznaků a uložení Id pro pozdější nahrání objektu z databáze. Objekt je po vykonání konstruktoru "prázdnou schránkou", duchem (GHOST), který načte svá data z databáze teprve tehdy, když použijeme některou metodu nebo vlastnost pracující s instančními a perzistovanými proměnnými. Z hlediska uživatele naší třídy (myšleno programátora)  je ale vše ve starých kolejích - rozhraní objektu bude reagovat tak, jak očekává,  a existenci pozdní incializace objektu (Lazy Load) může ignorovat. Poslední větu si přečtěte ještě jednou a tiše s k ní přidejte pravidlo: Nikdy nesmím nutit uživatele svých tříd volat nějaké speciální "Init" metody předtím, než začnou s třídou pracovat. Jedinou legální "Init" metodou je konstruktor.
  2.  Jak k pozdní incializaci a tedy nahrání dat objektu dojde? Vlastnosti, jejichž hodnoty jsou uložené v databázi (Id zákazníka jako klíč v tabulce Objednávek a popisek (Description) objednávky) mají na prvním řádku svých get/set přístupových metod volání metody TriggerLoad. Jak víme, jde o volání metody z BusinessObjectBase, která sama rozhoduje, zda již byla data objektu nahrána z databáze. Pokud data nebyla nahrána, třída BusinessObjectBase řídí scénář nahrávání objektu v metodě Load. Jestliže jsou data pro objednávku v třídě DataCacheHelper, je volána metoda DoInternalLoad(DataRow row), která načte data objednávky z předaného řádku. Když v třídě DataCacheHelper data pro aktuální instanci nemáme, BusinessObjectBase volá variantu metody DoInternalLoad bez argumentů. Metoda DoInternalLoad vyzvedne řádek z databáze s využitím databázové komponenty (což je Singleton nebo Thread specific storage - jednoduše třída zapoudřující  API pro práci s datovým zdrojem) a tento řádek předá své stejně nazvané sestřičce, o níž byla řeč výše.
    Důležité je, že celý scénář nahrávání řídí bázová třída - v odvozené třídě jen v přesně vymezených bodech scénáře "dosazuje" třída Order své vlastní specifické chování a používá své speciální atributy.
  3. V set přístupových metodách u vlastností využíváme metodu CheckEquals z BusinessObjectBase. Jak už víte z minulého spotu, metoda CheckEquals zkontroluje rovnost dvou objektů a podle toho nastaví příznak IsDirty - byl objekt změněn proti datům v databázi a musí tedy dojít k jeho uložení?
  4. Jak je to nahráním položek objednávky  - vlastnost Items? Často se stává, že potřebujete pracovat se samotným objektem, ale je zbytečné při nahrání dat objektu  z databáze ihned plnit i všechny jeho kolekce. Kolekce Items je naplněna při prvním přístupu ke kolekci  - příznak, zda byla kolekce nahrána nese pomocná instanční proměnná m_itemsLoaded. Jestliže kolekce naplněna nebyla, je volána privátní metoda loadItems, v níž s pomocí databázové komponenty vyzvedneme z databáte všechny položky objednávky - filtrem, který je použit v SQL dotazu je samozřejmě Id objednávky. Poté projdeme vrácenou tabulku a všechny řádky uložíme do třídy DataCacheHelper. Zde přepokládáme, že metoda DbComponent.Instance.OrderItem_GetByOrderId, vrací z databáze všechna data potřebná pro obnovení objektu z databáze, nejen jejich Id. To je běžná praxe, pokud máte uloženou proceduru, která vybírá záznamy z jedné tabulky (pro jednu třídu) podle různých podmínek. Důležité je, že za pomoci identitní mapy (Identity Map) sestrojíme objekty - "duchy" - OrderItem, kterým předáme jejich Id,  a třída BusinessObjectBase již zajistí, že když instance OrderItem budou chtít nahrát svá data z databáze, tak jí bude vrácen řádek uložený v instanci třídy DataCacheHeper. To znamená, že třída OrderItem nebude zbytečně zatěžovat databázi duplicitními dotazy a přitom kontrola na existenci cachovaného řádku pro instance jakékoli třídy je součástí společného předka BusinessObjectBase a "nezasviníme" si stejným kódem celou business vrstvu.
  5. Metoda Order také přepisuje metodu DoInternalSave, v níž uloží své atributy do databáze. Jak uvidíme dále, metodě Order_Update předáváme hodnotu zděděného a bázovou třídou spravovaného příznaku IsNew - tento příznak metoda interně použije k rozhodnutí, zda provede SQL příkaz INSERT nebo UPDATE1. Opět - po volání metody Save uživatelem jen třída BusinessObjectBase jakožto finální instance rozhoduje, zda je potřeba data ukládat a zda je tedy vubec nutné a účelné volat metodu DoInternalSave. Opět vidíte čistý řez mezi kontrolou, kdy je nutné objekt uložit (třída BusinessObjectBase),  a samotným ukládáním (třída Order i další potomci BusinessObjectBase). Kromě uložení vlastních hodnot odpovídá třída za uložení agregovaných objektů OrderItem. Proto v metodě DoInternalSave nejprve zkontroluje, jestli byly objekty v kolekci nahrány (příznak m_itemsLoaded) a pokud ano, tak jen zavolá pomocnou metodu SaveCollection, která je implementována, jak jinak že;), v třídě BusinessObjectBase.

I když z příkladu byste měli začít tušit, proč je BusinessObjectBase tak výhodná, stále neřešíme některé problémy.

  1. V příkladu není vůbec řešeno odebírání a přidávání položek do kolekce - to znamená nastavování/zrušení "rodiče" u agregovaných objektů. Nijak jsme neřešili m:n relace a odpovědnost za zakládání/rušení záznamů ve vazebních tabulkách. Myslíte, že i zde půjde využít třída BusinesObjectBase? ;)
  2. Co když si budeme chtít u některých potomků  BusinessObjectBase "vynutit" jiné chování - třeba zamezit použití DataCacheHelperu?
  3. A co transakce? V našem příkladu zatím nijak neřešíme ukládání objektů v transakci, což bychom měli, protože určitě nechceme mít v systému objednávky s polovinou objednaných položek. Jaký objekt má spouštět a řídit transakci? Kdo musí ošetřit chyby vzniklé při ukládání objektu?

To be continued... :)

Poznámky:

  1. Jsem si vědom střídavé soudržnosti metody související s "přepínačem" IsNew . V dalších dílech bude vysvětleno, proč střídavá soudržnost zrovna u této metody nevadí.


Sunday, 05 February 2006 14:44:36 (Central Europe Standard Time, UTC+01:00)       
Comments [7]  Návrhové vzory