Ígéretemhez híven folytatom tervezési mintákat bemutató cikksorozatomat.
Az egyik legalapvetőbb és valószínűleg leggyakrabban használt minta az egyke minta. A neve is mutatja legfőbb jellemvonását: az adott osztályból egyetlen példány jön létre az alkalmazás futása során.
Erre akkor van szükség, ha az adott objektumból felesleges, sőt zavaró lenne több példányt létrehozni; jó példa erre a hibanaplózó vagy teszem azt az XML-feldolgozó osztály.
A cél tehát egy olyan módszer bevezetése, amely garantálja, hogy mindössze egy objektumot lehet létrehozni az osztályból.
Az első, szembeötlő nehézség az, hogy az osztály konstruktorát bárki meg tudja hívni - ezt kell megakadályozzuk.
A megoldás a konstruktor elrejtése - tegyük priváttá, és ezzel megakadályozzuk a közvetlen példányosítást. Azonban valahogy biztosítanunk kell az osztály példányosítását, hiszen különben mindössze egy használhatatlan osztályt kaptunk.
Ezt a célt szolgálja az Instance() tagfüggvény, amely az egyetlen osztálypéldány létrehozásáért felelős.
Az osztály egyetlen példánya az első Instance() hívás során jön létre, az ezt követő hívások pedig ezt a példányt adják vissza.
Egy Singleton osztály (avagy Egyke) létrehozásának menete:
- rejtsük el a ctor-okat, a másoló ctor-t és az "operator =" -t (ezáltal lehetetlenné tesszük a közvetlen példányosítást)
- deklaráljuk az adattaghoz történő hozzáférését biztosító, static public metódust (általában Instance() névre hallagat)
- deklaráljuk az osztály példánymutatóját statikus privát adattagként (ez az adott osztályra egyetlen példányának címe)
- gondoskodjunk arról, hogy az első hozzáféréskor létrehozzuk az egyetlen osztálypéldányt, minden azt követő híváskor pedig a már létező objektumpoinetrt adjuk vissza
Kérdés
Miért statikus az Instance() metódus? Hamarosan jön a kézenfekvő magyarázat, de előbb vizsgáljuk meg a kódot:
public class Singleton
{
// példány
private static Singleton instance;
public static Singleton Instance()
{
// csak akkor hozzuk létre,
// ha korábban ez nem történt meg
if (instance == null)
{
instance = new Singleton();
}
return instance;
};
public void fv()
{
//...
};
// ctor-ok és az értékadó operátor elrejtése, a közvetlen példányosítás megakadályozására
private Singleton() {};
private Singleton( const Singleton& );
private Singleton& operator =( const Singleton& );
}
A következő kódrészlet a példányosítás módját mutatja be:
// a kliensoldali kód
int main()
{
// egyke létrehozása / lekérdezése
Singleton obj = Singleton.Instance();
obj.fv()
//...
}
Az előző kérdésre - azaz, hogy miért static az Instance() tagfüggvény? - a fenti kódrészletben található a válasz: az osztálynak eredetileg nincs érvényes példánya, és érvényes példánymutató nélkül pedig nem tudunk meghívni nem-statikus tagfüggvényeket.
A statikus függvények kivételt képeznek, hiszen az osztálypéldány megléte nem előfeltétel. (A statikus függvények korlátja, hogy kizárólag statikus adattagokon dolgozhatnak.)
Az egyik felmerülő gond a fenti Singleton megvalósítással a konkurens hozzáférés. Ha több szálból (nagyjából) egyszerre hívják az Instance() függvényt, előfordulhat,
hogy az if( instance == null ) ellenőrzést egyszerre hajtják végre, majd több példány is létrejön, hiszen a feltétel egyik szálnál sem teljesült.
Erre természetesen vannak megfelelő megoldások és nyelvi elemek, de a többszálúság rejtelmeibe egyelőre nem szeretnék jobban belemenni (mindazonáltal egy következő cikksorozat témája lehet, addig meg hagyatkozzatok google barátunkra ;-)).
További jó kódolást mindenkinek!
Nyisztor Károly
www.nyisztorkaroly.org
| < Előző | Következő > |
|---|





