4.4. Příklad jednoduché komponenty

Předpokládejme, že chceme vytvořit komponentu, která bude umět generovat pseudonáhodná čísla v intervalu od 0 do 32767. Aby řady generovaných čísel nebyly vždy stejné, umožníme inicializaci generátoru nějakou startovací hodnotou. Řešení si nejprve ukážeme v „čistém“ C++, tedy bez použití a dodržení specifikace COM.

Rozhraní komponenty bychom mohli v C++ popsat abstraktní třídou IRandom, která má dvě metody. Metoda Start určuje inicializační hodnotu generátoru a metoda Next poskytuje další pseudonáhodné číslo v řadě.

src/RandomCpp/IRandom.h
Příklad 4.1. Rozhraní IRandom.h
   struct IRandom {
      virtual void Start(int seed) = 0;
      virtual int Next() = 0;
   };

Znaky "= 0" za hlavičkami metod říkají, že tyto metody jsou abstraktní a nemají tedy žádnou implementaci. Třída obsahující abstraktní metody musí být implementována jinou konkrétní třídou, která zdědí toto rozhraní a všechny abstraktní metody implementuje.

src/RandomCpp/RandomImpl.h
Příklad 4.2. Implementace komponenty RandomImpl.h
   # include "IRandom.h"
 
   class CRandomImpl: public IRandom {
   protected:
      int m_seed;
   public:
      // konstruktor
      CRandomImpl(): m_seed(0) {}

      // inicializace generované řady
         void Start(int seed) { 
         m_seed = seed; 
      }

      // generování další hodnoty v řadě
      int Next() { 
         m_seed = m_seed * 3925 + 28347; 
         return m_seed & 0xffff; 
      }
   };

Nyní již můžeme generátor náhodných čísel použít v testovací aplikaci. Ta například provede nastartování generátoru nějakou konkrétní hodnotou a zobrazí prvních deset vygenerovaných čísel.

src/RandomCpp/RandomTest.cpp
Příklad 4.3. Testovací aplikace RandomTest.cpp
# include "RandomImpl.h"

void main(int argc, char** argv)
{
   // vytvoříme instanci komponenty
   IRandom* rnd = new CRandomImpl();

   // použijeme komponentu v aplikaci
   rnd->Start(1234);
   for( int i = 0; i < 10; i++) {
      cout << i << ": " << rnd->Next() << endl;
   }

   // zrušíme instanci komponenty
   delete rnd;
}

Nejprve tedy vytvoříme samotnou komponentu a získáme ukazatel na rozhraní, pomocí kterého budeme dále s komponentou komunikovat. Až nebudeme komponentu dále potřebovat, zrušíme ji.

Úkol k textu
Vytvořte novou verzi komponenty generátoru náhodných čísel doplněním dalšího rozhraní, které navíc umožní generování reálných čísel v intervalu 0.0 až 1.0. Rozšíření proveďte tak, aby byla stále zachována možnost pracovat s komponentou prostřednictvím původního rozhraní.

Úkol k zamyšleníÚkol k zamyšlení
Zamyslete se nad tím, které vlastnosti uvedeného řešení brání tomu, aby mohla být aplikace zcela nezávislá na implementaci komponenty, a pokuste se navrhnout řešení. Proč do kódu aplikace vkládáme záhlaví RandomImpl.h a ne pouze IRandom.h? Jaké problémy nastanou, pokud komponentu bude současně používat více klientů?