2010. július 2., péntek

Az Egyke (Singleton) tervezési minta

Egy nagyon jó kis cikket találtam a tervezési mintákkal kapcsolatban Nyisztor Károly tollából, amit C#-ban meg is valósítottam. A bejegyzés és a forrás itt olvasható:

Az Egyke (Singleton) tervezési minta

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 hallgat)
  • 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:
   using System;

public sealed class Singleton
{
private static volatile Singleton instance;
private static object syncRoot = new Object();

private Singleton() { }

public static Singleton Instance
{
get
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
instance = new Singleton();
}
}
return instance;
}
}
}
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...

Eddig tartott Nyisztor Károly remek bejegyzése. Természetesen a többszálúsággal kapcsolatos problémát a fenti kód már orvosolja. Ezzel kapcsolatban további információkat az alábbi linken találhatunk: msdn
További jó kódolást mindenkinek!

0 megjegyzés :

Megjegyzés küldése