» »

[ OOP ] Global vs. Not Global

[ OOP ] Global vs. Not Global

BigWhale ::

Nadaljevanje razprave o globalih in kako se jih znebiti...

Kopernik, hvala za kodo. Moj 'problem' je takle, da se malo bolj podrobno opisem...

Imam nek plugin, ta plugin v svojem konstruktorju poskrbi, zato, da se nalozi tudi objekt, ki predstavlja GUI za ta plugin. No in sele ta gui potrebuje dejansko konekcijo na bazo. Obstaja tudi factory za ta plugin. Vse lepo in prav, da vidim, ce sem prav razumel tvojo kodo.

Naredim plugin za connect na DB, ta plugin se poveze na bazo, etc, etc... Ko naredim svoj plugin, ki kdaj pa kdaj nuca bazo enostavno 'poklicem' se factory in recem 'naj naredi eno instanco tega plugina'...

Hm, nevem, nevem...

Da se enkrat premeljem...

Naredi plugin, ki bo skrbel za dostop do baze.
Naredi klienta.
Povej klientu, da naj nalozi db plugin.
Ustvari se x clientov (drugih), ki vsak zase spet uporabijo db plugin.

Zanimiva ideja, priznam. Ampak ali je to res bolj pregledno in ucinkovito, kot en extern?

Kaj pa ce nimam nekih pluginov in nevem cesa se? Samo en program, razsut na 20 razlicnih filetkov in knjiznic?

Kako bo class jodel vedel, da sem jaz povezan na bazo? Mu bom ob tem, ko ga bom instanciral moral povedati kje je baza? As in:

jodel foo = new jodel("some param", dbpointer);
foo->get_bloody_data();

Gundolf ::

jodel foo = new jodel("some param", dbpointer);
foo->get_bloody_data();

Ta koda se meni zdi cisto v redu (razen mankajocega *).
Morda se boljsa bi bila

jodel foo("some param");
foo.get_bloody_data(dbpointer);

To pa res ne rabis nobene globalne spremenljivke, ki ti pove ce si povezan na bazo. Taka koda je bolj pregledna in med drugim razsirljiva. Zdaj imas lahko npr. povezavo na vec razlicnih baz, kar je bilo prej nemogoce. Ok, ni ne vem kako zelo uporaben feature ampak recimo da niso vedno baze v vprasanju.

BigWhale ::

Ok, fair enough... Ampak od kje ti dbpointer?

al je blo to misljeno, da je dbpointer tisto kar ti vrne zadeva?

Gundolf ::

Ne vem od kje dbpointer, ti si ga zacel uporabljati :D
Jah dbpointer je misljen kot nekaj, kar ti 'kaze' na tvojo bazo. Oziroma kar sam objekt, ki predstavlja bazo. Morda kaj v tem smislu. Vsaj tako sem si ga jaz predstavljal.

Vesoljc ::

jodel foo("some param");
foo.get_bloody_data( DataBaseFactory::OpenMySpecialDataBaseWhichIsLocataedSomewhereSpecial( DataBasePath ) );


:))
Abnormal behavior of abnormal brain makes me normal...

BigWhale ::

Jao, ja... bila je pozna ura... :P Ce izhajam spet iz tega:

> Naredi plugin, ki bo skrbel za dostop do baze.
> Naredi klienta.
> Povej klientu, da naj nalozi db plugin.
> Ustvari se x clientov (drugih), ki vsak zase spet uporabijo > db plugin.

Na koncu pridem do tega, da mora vsak 'client' instancirati database driver. Nevem, ce je to dosti bolj prikladno kot imeti en extern. Jaz imam se vedno bazo 'skrito' in je client neodvisen od nje.

No, seveda je cela stvar odvisna od implementacije in platforme na kateri delas.

Gundolf ::

Zakaj bi moral to vsak client delati?

> Naredi plugin, ki bo skrbel za dostop do baze.
naredis objekt - database
> Naredi klienta.
naredis drug objekt - client
> Povej klientu, da naj nalozi db plugin.
client.load(database)
> Ustvari se x clientov (drugih), ki vsak zase spet uporabijo > db plugin.
clientN[x].load(database)

Po moje govoriva vsak o svoji stvari :\ Meni se zdi da je vsa razlika med tvojo kodo in mojo predlagano, s katero bi se znebil globalnega s..... ta, da moras v mojem primeru vsem objektom podati se eno spremenljivko (pointer, referenco, whatever). Vsekakor clienti ne dobijo nobenega overheada zaradi tega. Baza ostane skrita in clienti se bolj neodvisni od nje.

BigWhale ::

> Po moje govoriva vsak o svoji stvari [:\\] Meni se zdi da

Najbrz res ja... :))

> je vsa razlika med tvojo kodo in mojo predlagano, s katero
> bi se znebil globalnega s..... ta, da moras v mojem primeru
> vsem objektom podati se eno spremenljivko

Tocno! Hm, to je lepse, kot imetin eno globalno spremenljivko?

No ja, okusi so razlicni... ;)

Gundolf ::

Veliko lepse je, ce ima vsak objekt svojo spremenljivko kot pa da jo naredis globalno. Saj sem ze rekel, da je tu tudi moznost razsiritve, ki jo pri globalni spremenljivki nimas.

Je pa vsekakor lepse za koga, ki mora gledati v tvojo kodo. Globalne spremenljivke moras iskat po vsej kodi, po vseh fajlih, medtem ko lokalne spremenljivke so pa - lokalne :D

Ce pa vseeno pod nobenim pogojem noces lokalnih spremenljivk in imas vedno le 1 bazo (ali kaj drugega) potem si pa poglej singleton. Za pokusino bom tule napisal primer (drugace je to design pattern v recimo knjiznici Loki ali pa Boost in ga je se lazje napisati pa se veliko bolje je organiziran).

// only one instznce of SingletonDB class is ever required
class SingletonDB {
   static SingletonDB* theOne;

   // omejitev: konstruktor nima parametrov
   SingletonDB()  {}
public:
   static SingletonDB* instance() {
      if (theOne == 0)
         theOne = new SingletonDB;
      return theOne;
   }

   // ostalo pa skoraj identicno implementaciji baze
   // oz. pointerja (ali handlea) na bazo
};

// tole gre v .cpp fajl, zgornje pa lahko v header
SingletonDB* SingletonDB::theOne = 0;


Zdaj ti lahko vsak tvoj client dostopa do baze takole:
SingletonDB::instance()->


Znebis se globalnih spremenljivk, sploh pa extern (se posebno tecna sorta IMHO, ker za njih ne ves kje so definirane) spremenljivk, vsak objekt, ki hoce uporabljati bazo mora includati zgornji header, vse je bolj pregledno.

BigWhale ::

> Globalne spremenljivke moras iskat po vsej kodi, po vseh
> fajlih, medtem ko lokalne spremenljivke so pa - lokalne

Ma ja no, saj pravim ob primerni uporabi so globali cisto ok resitev.

Pri meni so vse deklaracije v globals.h, vrednosti se pa prirejajo bolj ali manj na enem mestu ob startu programa. Globalne spremenljivke so pri meni bolj ali manj konstante.

Gundolf ::

Sicer vem da bom s tem vprasanjem izdal totalno svoje nepoznavanje globalnih spremenljivk, ampak bm vseeno tvegal. Ali ni treba spremenljivke definirati v nekem .cpp fajlu? To sprasujem, ker pravis "Pri meni so vse deklaracije v globals.h"

Vesoljc ::

// header
extern CLogger* gpLog;

// source
CLogger* gpLog = 0;
Abnormal behavior of abnormal brain makes me normal...

BigWhale ::

V mojem primeru je tako, da imam cca 5 pluginov, ki so sami zase neodvisni in pa glavni program, ki nalaga te plugine.

Zdaj, ce bi jaz delal stvari 'tako kot treba' potem bi bili te plugini 100% neodvisni ampak niso. Se vedno imajo skupno bazo in nekaj malenkosti (user settings in tako naprej).

Vsak plugin je svoj .so library. Potem je tukaj se main, ki skrbi za nalaganje teh pluginov. Vsi skupaj pa uporabljajo en common library, ki vsebuje dolocene funkcije, ki so vsem skupni.

Jaz imam v globals.h deklarirano recimo

QSqlDatabase *defaultDB;

Ta header je includan samo v mainu, drugje pa nikjer, ker drugace pride do konfliktov pri linkanju, ko se common lib linka z ostalimi knjiznicami. Definicija defaultDB se prav tako naredi v mainu.

V tistih cpp-jih kjer potem potrebujem defaultDB potem samo extern deklaracijo naredim.

extern QSqlDatabase *defaultDB;

Tako je problem resen.

Najbrz ni idealna resiteva ampak je pa precej prirocna, ker ni treba tega pointerja vlacit naokrog po vseh objektih in pingpongat sem ter tja. Kode je precej manj, performance je IMO isti. Preglednost? Nevem, meni je stvar cisto pregledna :))

Gundolf ::

Ja glede performanc ni treba skrbet, dvomim da je sploh kak razlika med uporabo globalnih spremenljivk in ce bi isto naredil lokalno.

Vidim da header includas le v enem fajlu in ti v bistvu sploh ne sluzi kot header, zato bi ga lahko celo preimenoval v .cpp, ampak brezveze, ce se tebi zdi pregledno pac delaj tako kot dozdaj. Jaz vem da kaj takega v svoji kodi sploh ne bi mogel gledati in bi koj polokaliziral :D Se sploh ce to uporabljajo tudi plugini - fuj.

noraguta ::

kako pa lahko lokalno lockaš globalne varibale(z CS), ako ne poznaš celotnega flowa aplikacije ne da bi stem zajebal druge??? mutexi pač niso odgovor ker degradirajo performance. kako potem hendlaš napake v db connectionu če pride le do tega??? implementiraš visitor pattern da obvestiš le vse komponente da je prišlo do neljubega dogodka?


v global sodijo enumi in konstante , razen ce ne delaš sam in imaš vse v glavi , v ostalem omejuješ scope. na to kar je relavantno in ga fillaš le z dato , katera spada tja. drugače se boš zaklal, čisto preprosto. če stvar ni prezahtevna kamot zdefiniraš scope classe in jih po potrebi inheritaš , c++ pozna multiple inheritance in jih namečeš pač po potrebi. še bolje je pa kopernikov pristop.
Pust' ot pobyedy k pobyedye vyedyot!


Vredno ogleda ...

TemaSporočilaOglediZadnje sporočilo
TemaSporočilaOglediZadnje sporočilo
»

[C++]Uporaba strukture v drugi .cpp datoteki

Oddelek: Programiranje
143139 (2842) mallard
»

Qt Designer -> KDevelop C++ Error

Oddelek: Programiranje
352130 (1660) 'FireSTORM'
»

[c++] globalne spremenljivke (extern)

Oddelek: Programiranje
71596 (1469) Vesoljc
»

[C++] for {}

Oddelek: Programiranje
291723 (1417) Gundolf
»

Coding Style

Oddelek: Programiranje
433473 (2665) 64202

Več podobnih tem