Ugrás a tartalomhoz

„Egyke programtervezési minta” változatai közötti eltérés

A Wikipédiából, a szabad enciklopédiából
[ellenőrzött változat][ellenőrzött változat]
Tartalom törölve Tartalom hozzáadva
→‎Megvalósítása: lusta példányosítás
31. sor: 31. sor:
public static Singleton getInstance() {
public static Singleton getInstance() {
return INSTANCE;
return INSTANCE;
}
}
</source>

Az egyke használható lusta inicializációval. Ekkor a példány csak az osztálymetódus első hívásakor jön létre. Ha ezt párhuzamos környezetben használják, akkor biztosítani kell, hogy ne legyen race condition, különben több szál is létrehozhat egy példányt, ami kritikus a rendszer szempontjából, és annak összeomlását okozhatja. A következő Java példa duplán ellenőrzött zárolással használja a lusta példányosítást, így biztosítva a szálbiztosságot.

<source lang="java">
public final class Singleton {
private static volatile Singleton instance = null;

private Singleton() {}

public static Singleton getInstance() {
if (instance == null) {
synchronized(Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
}
}

A lap 2017. május 22., 18:23-kori változata

Az egyke programtervezési minta olyan programtervezési minta, amely egy objektumra korlátozza egy osztály létrehozható példányainak számát. Gyakori, hogy egy osztályt úgy kell megírni, hogy csak egy példány lehet belőle. Ehhez jól kell ismerni az objektumorientált programozás alapelveit. Az osztályból példányt a konstruktorával lehet készíteni. Ha van publikus konstruktor az osztályban, akkor akárhány példány készíthető belőle, tehát publikus konstruktora nem lehet az egykének. De ha nincs konstruktor, akkor nem hozható létre a példány, amin keresztül hívhatnánk a metódusait. A megoldást az osztályszintű (statikus) metódusok jelentik. Ezeket akkor is lehet hívni, ha nincs példány. Az egykének tehát van egy osztályszintű metódusa (szerezPéldány, angolul getInstance), ami minden hívójának ugyanazt a példányt adja vissza. Természetesen ezt a példányt is létre kell hozni, ehhez privát konstruktort kell készíteni, amit a szerezPéldány az egyke osztály tagjaként meghívhat.[1]

Néhányan vitatják az egyke mintát, és antimintának tekintik, mivel olyankor is használják, amikor nem célszerű. Ezzel szükségtelen korlátozásokat vagy globális állapotokat vezetnek be.[2][3][4]

Felhasználása

Egykét csak akkor érdemes használni, ha a rendszer működhetne rendellenesen, vagy akár össze is omolna, ha abból az osztályból több objektumot is lehetne példányosítani. A homlokzatok gyakran egykék, mivel csak egy homlokzatra van szükség. Ilyenek még az állapot objektumok is.

  • Nem szennyezik a névteret szükségtelen változókkal.
  • Lehetővé teszik a lusta allokációt és inicializációt, míg a globális változók mindig fogyasztanak erőforrásokat.

Megvalósítása

A megvalósításnak biztosítania kell, hogy:

  • mindig egyetlen objektum létezik
  • mindig legyen globális hozzáférés a példányhoz

Ezt rendszerint így érik el:

  • minden konstruktor privát
  • osztálymetódus, ami visszaad egy referenciát a példányra

A példányt rendszerint privát osztálypéldányként tárolják. A példány a változó inicializálásával jön létre, valamivel azelőtt, hogy az osztálymetódust meghívják. A következő egyszerű implementáció Javában készült:

public final class Singleton {
    private static final Singleton INSTANCE = new Singleton();

    private Singleton() {}

    public static Singleton getInstance() {
        return INSTANCE;
    }
}

Az egyke használható lusta inicializációval. Ekkor a példány csak az osztálymetódus első hívásakor jön létre. Ha ezt párhuzamos környezetben használják, akkor biztosítani kell, hogy ne legyen race condition, különben több szál is létrehozhat egy példányt, ami kritikus a rendszer szempontjából, és annak összeomlását okozhatja. A következő Java példa duplán ellenőrzött zárolással használja a lusta példányosítást, így biztosítva a szálbiztosságot.

public final class Singleton {
    private static volatile Singleton instance = null;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized(Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

C# példakód

using System;
namespace Singleton {
	public class Singleton {
		// statikus mező az egyetlen példány számára
		private static Singleton uniqueInstance = null;
		// privát konstruktor, hogy ne lehessen 'new' kulcsszóval példányosítani
		private Singleton() {}
		// biztosítja számunkra a példányosítást és egyben visszaadja a példányt
		// mindenkinek ugyanazt
		public static Singleton getInstance() {
			if (uniqueInstance == null) // megvizsgálja, hogy létezik-e már egy példány
			{
				uniqueInstance = new Singleton(); // ha nem, akkor létrehozza azt
			}
			// visszaadja a példányt
			return uniqueInstance;
		}
	}
	class Program {
		static void Main(string[] args) {
			//a konstruktor private, nem lehet new kulcsszóval példányosítani
			Singleton s1 = Singleton.getInstance();
			Singleton s2 = Singleton.getInstance();
			// Teszt: ugyanaz a példány-e a kettő?
			if (s1 == s2) {
				Console.WriteLine("Ugyanaz! Tehát csak egy példány van.");
			}
			Console.ReadKey();
		}
	}
}

Szálbiztos egyke C# példakód

using System;
namespace SingletonThreadSafe {
	public sealed class Singleton {
		// A statikus konstruktor akkor fut le, amikor az osztályt példányosítjuk,
		// vagy statikus tagra hivatkozunk ÉS egy Application Domain alatt
		// (értsd: adott program futásakor) maximum egyszer futhat le.
		private static readonly Singleton instance = new Singleton();
		// privát konstruktor külső 'new' példányosítás ellen
		private Singleton() {}
		// statikus konstruktor
		// Azon osztályok, melyek nem rendelkeznek statikus 101
		// konstruktorral beforefieldinit attribútumot
		// kapnak az IL kódban. A statikus tagok inicializációja
		// a program kezdetén azonnal megtörténik.
		// Az olyan osztályok, amelyeknek van statikus konstruktora
		// ezt nem kapják meg,
		// ezért a statikus tagok akkor példányosulnak,
		// amikor először hivatkozunk az osztályra,
		// vagyis jelen esetben amikor elkérjük a példányt.
		static Singleton() {}
		public static Singleton Instance {
			get {
				return instance;
			}
		}
	}
	class Program {
		static void Main(string[] args) {
			Singleton s1 = Singleton.Instance;
			Singleton s2 = Singleton.Instance;
			if (s1 == s2) {
				Console.WriteLine("OK");
			}
			Console.ReadKey();
		}
	}
}
  1. http://aries.ektf.hu/~hz/pdf-tamop/pdf-xx/ProgTechJegyzet.1.1.6.pdf
  2. Scott Densmore. Why singletons are evil, May 2004
  3. Steve Yegge. Singletons considered stupid, September 2004
  4. Clean Code Talks - Global State and Singletons