tifyty

pure Java, what else ?

Miért kell a lusta egyke

Ugye a Bill Pugh féle lazy singleton implementáció:

public class Singleton {
        // Private constructor prevents instantiation from other classes
        private Singleton() { }
 
        /**
        * SingletonHolder is loaded on the first execution of Singleton.getInstance() 
        * or the first access to SingletonHolder.INSTANCE, not before.
        */
        private static class SingletonHolder { 
                public static final Singleton INSTANCE = new Singleton();
        }
 
        public static Singleton getInstance() {
                return SingletonHolder.INSTANCE;
        }
}

(Forrás, WikiPedia.)

Ez csak akkor hozza létre a singleton instance-ot, amikor arra először szükségünk van. És persze felmerül a kérdés, hogy miért kell a belső osztállyal nyűglődni, és miért nem jó a szokásos singleton, amelyik már a getInstance() meghívása előtt, az osztály betöltődésekor elkészíti azt az egy példányt. A szokásos válasz az, hogy sok esetben a példány létrehozása költséges, és nem is biztos, hogy minden futtattásnál szükséges. Rossz válasz, vagy ha sok 9gag-et olvasok, akkor “Bich please…”.

Ha már olyan sokáig tart létrehozni, akkor nem jobb ha akár egy aszinkron szálon a szerver indításakor végigviszem a létrehozás költséges taskjait? Inkább az első olyan kérést akasszam meg, amelyik kiszolgálásához kell a singleton? Vagy komolyan el tudja valaki képzelni, hogy egy komoly szerver alkalmazás esetében van olyan singleton, amelyik hónapokig tartó futás közben a következő maintenance reboot-ig nem kell egyszer sem? Akkor azért az nagyon szaglik, valaki nem mosott lábat!

Az ilyen kérdések ott motoszkálnak az ember fejében, aztán egyszer csak szembejön a válasz, amikor nem is várná, többnyire egy Null Pointer Exception személyében.

Történt egy szép napsütéses keddi délután, hogy kellett nekem egy olyan szingleton, amelyik egy Neo4j db factory-t ad vissza. Persze a Neo4j-nek, lokális adatbázis esetén kell egy könyvtár, ahol az adatbázis van, de ez nem probléma. Ehhez egy static public setter metódust deklaráltam, és …

A unit teszt olyan NPE-t produkált, mint annak rendje és módja. Mert igaz ugyan, hogy teszt első néhány sora az volt, hogy

        final String dbPath = "./target/db/";
        SingletonDbFactory.setDbPath(dbPath);
        SingletonRepositoryFactory<User> factory = (SingletonRepositoryFactory<User>) SingletonRepositoryFactory
                .getInstance();

de ez azt is jelentette, hogy mielőtt a setDbPath meghívódik, az osztály betöltődik, és létrejön az egyetlen instance ami bizony még nincs konfigurálva. Utána be lenne konfigurálva, és vissza is adná a getInstance() a még konfigurálatlanul létrehozott instance-ot, de persze az nem jött létre, mert beakasztott neki az NPE.

Na erre kell Bill Pugh megoldása. Nem a fenti hablaty.

One response to “Miért kell a lusta egyke

  1. v október 1, 2012 5:49 du.

    >>>
    Lehet, hogy csak en vagyok tul faradt, de mi az osszefugges a
    SingletonDbFactory es SingletonRepositoryFactory kozott?
    Hol kene latnom a NPE-t?
    Es hogy nezne ez ki a lusta egykevel?
    <<<

    Ha nem lazy a singleton, akkor azonnal létrejön egy példány, amelyik nem tudja, hogy hol van a könyvtár, ahol létre kellene hoznia az adatbázist, mert a hívási helyről a static metódusokat még nem hívtuk meg. Utána ugyan meg lehet hívni őket, de akkor már veszett fejsze nyele. Addigra a Neo4J megpróbálta létrehozni az adatbázist egy olyan String alapján, aminek az adatbázis könyvtárra kellene mutatnia, de közben az értéke null.

Vélemény, hozzászólás?

Adatok megadása vagy bejelentkezés valamelyik ikonnal:

WordPress.com Logo

Hozzászólhat a WordPress.com felhasználói fiók használatával. Kilépés / Módosítás )

Twitter kép

Hozzászólhat a Twitter felhasználói fiók használatával. Kilépés / Módosítás )

Facebook kép

Hozzászólhat a Facebook felhasználói fiók használatával. Kilépés / Módosítás )

Google+ kép

Hozzászólhat a Google+ felhasználói fiók használatával. Kilépés / Módosítás )

Kapcsolódás: %s

%d blogger ezt kedveli: