Deprecated: mysql_connect(): The mysql extension is deprecated and will be removed in the future: use mysqli or PDO instead in /home/www/novacisko.cz/subdomains/bredy/init.php on line 11

Warning: mysql_connect(): Headers and client library minor version mismatch. Headers:50562 Library:100020 in /home/www/novacisko.cz/subdomains/bredy/init.php on line 11

Warning: Cannot modify header information - headers already sent by (output started at /home/www/novacisko.cz/subdomains/bredy/init.php:11) in /home/www/novacisko.cz/subdomains/bredy/index.php on line 38
Serializace dat a objektů II - Návrh serializátoru - Bredyho blog - Ondřej Novák
Bredyho blog - Ondřej Novák

Serializace dat a objektů II - Návrh serializátoru

Po teoretickém úvodu o serializaci se podíváme (ještě stále teoreticky) na vlastní serializátor. Zatím si uděláme takovou jednoduchou analýzu


Jednoduchý serializátor

V předchozím článku jsme skončili u seznamu informací, které serializátor obdrží po čas serializace. Napišme si tedy mustr takového jednoduchého serializátoru.

class JednoduchySerializator {
public:
....
};

Serializátor získává informace o proměnných prostřednictvím volání operátoru závorky. Takže aby náš JednoduchýSerializátor bylo možné použít, musíme tento operátor definovat.

Protože parametrem operátoru je pokaždé proměnná jiného typu, musíme zajistit tolik verzí této funkce, kolik typů lze serializovat

class JednoduchySerializator {
public:
void operator()(int &x);
void operator()(unsigned int &x);
void operator()(float &x);
void operator()(double &x);
void operator()(std::string &x);
void operator()(bool &x);
void operator()(vykaz &x);
...
};

Takto napsaný jednoduchý serializátor naprost dostačuje k jednorázovému účelu a mnohdy to může být ideální řešení pro malé ad-hoc projekty. Teď postačí jen pro každý typ definovat způsob uložení do streamu (tedy formát) jako implementaci každé funkce a máme hotovo. Ovšem nezapomeňme, že budeme potřebovat třídu ve dvou variantách a to pro zápis a pro čtení.

Jednoduchý serializátor - vylepšení: rozšířitelnost

Výše navržené řešení je jednoduché, rychle hotové, ale má jednu zásadní nevýhodu. Velice špatně se rozšiřuje - Tato nevýhoda nás bude provázet celým dnešním dílem a budeme hledat různá řešení, jak problém vyřešit.

V okamžiku, když založíme novou třídu nebo typ, musíme náš jednoduchý serializátor naučit tento nový typ. Znamená to zejména zásah do zdrojového kódu serializátoru. To není praktické a při práci v týmu, kdy vyžadujeme univerzální řešení i nemožné.

Protože píšeme v C++, kde zpravidla každým novými typem je vždycky třída (nebo struktura), obohatíme náš jednoduchý serializátor o další fukci, tentokrát šablonu, ve smyslu "ostatní typy"

template<typename T>
void operator()(T &x);

a implementace bude jednoduchá

template<typename T>
void JednoduchySerializator::operator()(T &x) {
x.serialize(*this);
};

V zásadě jen připomínám to co jsme si řekli na začátku. Složené typy, jako třídy a struktury, jsou složeny s menších nerozdělitelných, ale serializovatelných částí. Každá serializovatelná třída definuje metodu serialize a v ní předpis, jak se serializuje. Pokud tedy serializujeme instanci nějaké třídy, náš jednoduchý serializátor zavolá metodu serialize a jako parametr dosadí sama sebe. Tím se instance třídy sama rozloží.

Tím se nám rapidně zvýši univerzálnost serializátoru. Stále tu však máme problémy, které to neřeší:

  • Ne všechny třídy lze obohatit o funkci serialize()
  • Pořád musíme vést dva serializátory, jeden pro zápis, druhý pro čtení.

Jednoduchý serializátor - vylepšení: serializace neserializovatelných tříd

Výše popsaný problém lze snadno vyřešit po vzoru prvního odstavce. Jednoduše tyto třídy zahrneme do jakéhosi seznamu standardních tříd a učiníme je serializovatelnými.

Tohle řešení není dobré, a ukážeme si, že naopak, následující řešení je lepší i pro tzv. standardní třídy a typy. Ač by se mohlo zdát, že neserializovatelných tříd (tedy těch, které nemají metodu serialize()) nebude mnoho, opak je pravdou. Jen si vemte třeba všechny třídy STL, nebo třídy MFC, pokud pracujete v týmu, určitě najdete spoustu tříd, které se serializací nepočítají. Předělávat je a zasahovat do fungujících zdrojáků není vždy dobrý nápad.

V minulém díle jsem navrhl řešit toto specializací nějaké šablony. Zavedli jsme šablonu Serializable

template<class T>
class Serializable;

Specializací můžeme definovat spoustu variant této třídy. Můžeme specializace definovat na různých místech v různých zdrojácích, tak jak se nám to zrovna hodí. Nemusíme tedy zasahovat do již existujících zdrojáků a serializace nějakých existujících tříd vyřešit definičním souborem někde vedle. Takto lze například vytvořit soubor stl_serializable.h a do něho nadefinovat serializační funkce pro všechny známe stl třídy.

Podívejme se, jak taková specializace bude vypadat třeba pro pair

template<typename T1, typename T2>
class Serializable< std::pair < T1, T2 > >
{
public:

template<typename Archive>
static void serialize(std::pair<T1,T2> &o, Archive &a)
{
a(o.first);
a(o.second);
}
};

Použití specializace třídy Serializable zapojíme do JednoduchéhoSerializátoru do šablony představující "ostatní"

template<typename T>
void operator()(T &x);

a implementace bude vypadat takto:

template<typename T>
void JednoduchySerializator::operator()(T &x) {
Serializable<T>::serialize(x,*this);
};

Tím jsme si ale rozbili rozšíření z předhozí kapitoly, a musíme to tedy napravit. Pro všechny typy, ke kterým neexistuje specializace šablony Serializable napíšeme výchozí verzi.

template<typename T>
class Serializable;
{
public:

template<typename Archive>
static void serialize(T &o, Archive &a)
{
o.serialize(a)
}
};

Analýza dalšího postupu

Ukázali jsme si jednoduchý serializátor, který lze používat jako obecný serializátor. Umíme ho naučit serializovat různé typy, bez nutnosti do jeho implementace zasahovat. Nicméně stále tu řešíme několik problémů

  • Volba směru serializace (zápis,čtení)
  • Formát serializace (jak se vůbec data budou zapisovat)
  • ... s tím souvisí hloubka rozkladu základních datových typů. Některé formáty umožňují zapisovat komplexnější datové typy a tak je zbytečné rozkládat,
  • Kam se serializovaná data posílají?

Výše zmíněné body jasně spějí k rozdělení problémů do několika komponent

Vlastní serializátor

By měl být styčným místem mezi jednotlivými objekty a výsledným proudem. Jeho úkolem je procházet jednotlivé proměnné a předávat je dál v souvislé posloupnosti

Formátovač / Parser

Jehož úkolem je přebírat získané informace od serializátoru a převádět z nebo na proud dat. Formátovač si přitom musí umět zvolit hloubku rozkladu datových typů. Musí umět rozhodnout, které typy umí nativně a které dál potřebuje rozložit. Například některý formátovač dokáže uložit vektor jako tabulku vět, jiný jej rozloží na číslo určující počet záznamu následovaný serializovanými záznamy.

Transportní modul

Tento modul už pouze přijímá data v serializované vpodobě a nějakým způsobem je zpracová, například je ukládá na disk nebo posílá po síti. Na opačné straně pak data čte, nebo přijímá a předává ke zpracování parseru.

I když jsem vyjmenoval tři komponenty, ve skutečnosti jich je pět. Pouze serializátor je týž na obou stranách. Formátovač data generuje, formátuje, parser data čte a rozpoznává. Transportní modul tvoří hlavně vstupní a výstupní proud.

Zhlediska variability nám tato organizace umožňuje určovat

  • co je předmětem serializace? - serializátor komunikuje se serializovanými objekty
  • formát výsledných dat - volba vhodného formátovače
  • cíl/zdroj dat - volba příslušného proudu.

Lze si připravit různé komponenty formátovače, například:

  • binární formátovač
  • strukturovaný binární formátovač
  • XML
  • FastRPC

Komponenty očekávají jednotné rozhraní na straně serializátoru a proto se již nemusí zabývat vlastním procesem serializace

Komponenty transportního modulu mohou být

  • diskový soubor
  • přenos po síti
  • konzole
  • přenos mezi procesy (IPC)
  • zápis dat do netypických kontejnerů (registr windows, atd)
  • součást interní komunikace v rámci aplikace například mezi vlákny.
serializace_blokove_schema.png

Příště

Seriál o serializaci nekončí, v příštím díle si představíme obecnější verzi serializátoru a budeme volit formát serializovaného výstupu, tedy spíš ukážeme, jak napsat moduly pro formátování a parsování tak aby spolupracovaly se serializátorem.

vytvořeno: 5.9.2008 23:43:52, změněno: 18.9.2008 11:48:15
Jsou informace v článku pro Vás užitečné?
  • (5)
  • (0)
  • (0)
  • (0)
  • (0)
Nick nebo OpenID
Vzkaz
 
16.9.2015 14:00:09

genuine ugg boots

discount uggs boot
genuine ugg boots http://bootscheap.co.uk/
6.9.2015 08:15:04

discount uggs online

ugg outlet uk
discount uggs online http://bootscheap.co.uk/
5.9.2015 23:00:37

converse tw

Ь converse
converse tw http://conversetw.seofilter.org/
16.8.2015 13:06:17

converse

converse
27.7.2015 16:33:41

new balance taiwan

new balance
25.7.2015 00:01:56

new balance

new balancę
18.7.2015 15:53:58

new balance ̨

new balance
26.6.2015 17:09:06

toms in singapore

toms shoes singapore outlet
toms in singapore http://www.seofilter.org/

Podobné články

Serializace dat a objektů

Následující článek je úvodem do další série o generickém programování (šablony), nyní se zaměříme na problém perzistentního ukládání dat nebo jejich transport, obecně o serializaci a deserializaci dat

Serializace dat a objektů IV - Transport a struktura

Dnešní díl o serializaci se pozastaví nad nejvhodnější implementací transportního modulu a pak se vrhneme na strukturu dat.

Serializace dat a objektů III - Volba formátu

V našem seriálu o serializaci si tentokrát ukážeme, jakým způsobem budeme volit formát výsledného streamu. Nepůjde o konkrétní formáty, ale o způsoby, jak různé formáty implementovat

Multithreading v C++ (ve Win32)

Představení knihovny pro multithreading v C++. Jedná se čistě o objektový návrh multithreadingu inspirovaný Javou. Mnoho programátorům může usnadnit práci s vícero vlákny ve WinApi.

Blesk už to ví (rovná daň)

Na stránkách blesku vyšla tabulka výpočtu daňe podle nového systému rovné daně navrhované ODS. Zřejmě v Blesku mají víc informací než samotní politici...
Reklama: