Ugrás a tartalomhoz

Egyke programtervezési minta

A Wikipédiából, a szabad enciklopédiából
A lap korábbi változatát látod, amilyen 77.110.128.237 (vitalap) 2020. november 20., 21:51-kor történt szerkesztése után volt. Ez a változat jelentősen eltérhet az aktuális változattól. (Kód lefordítása, C# kód idiomatikusabb formázása)
Az egyke programtervezési minta UML osztálydiagramja

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 Egyke {
    private static final Egyke PELDANY = new Egyke();

    private Egyke() {}

    public static Singleton aPeldany() {
        return PELDANY;
    }
}

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 Egyke {
    private static volatile Egyke peldany = null;

    private Egyke() {}

    public static Egyke aPeldany() {
        if (peldany == null) {
            synchronized(Egyke.class) {
                if (peldany == null) {
                    peldany = new Egyke();
                }
            }
        }
        return peldany;
    }
}

C# példakód

using System;

namespace Egyke
{
	public class Egyke
	{
		// statikus mező az egyetlen példány számára
		private static Egyke egyediPeldany = null;

		// privát konstruktor, hogy ne lehessen 'new' kulcsszóval példányosítani
		private Egyke() {}

		// biztosítja számunkra a példányosítást és egyben visszaadja a példányt
		// mindenkinek ugyanazt
		public static Egyke aPeldany()
		{
			if (egyediPeldany == null) // megvizsgálja, hogy létezik-e már egy példány
				egyediPeldany = new Egyke(); // ha nem, akkor létrehozza azt

			// visszaadja a példányt
			return egyediPeldany;
		}
	}

	class Program
	{
		static void Main(string[] args)
		{
			//a konstruktor private, nem lehet new kulcsszóval példányosítani
			Egyke s1 = Egyke.aPeldany();
			Egyke s2 = Egyke.aPeldany();

			// 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 EgykeFonalBiztos
{
	public sealed class Egyke
	{
		// 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 Egyke egyed = new Egyke();

		// privát konstruktor külső 'new' példányosítás ellen
		private Egyke() {}

		// 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 Egyke() {}

		public static Egyke Peldany
		{
			get
			{
				return egyed;
			}
		}
	}

	class Program
	{
		static void Main(string[] args)
		{
			Egyke s1 = Egyke.Peldany;
			Egyke s2 = Egyke.Peldany;

			if (s1 == s2)
				Console.WriteLine("OK");

			Console.ReadKey();
		}
	}
}

Jegyzetek

Fordítás

Ez a szócikk részben vagy egészben a Singleton pattern című angol Wikipédia-szócikk fordításán alapul. Az eredeti cikk szerkesztőit annak laptörténete sorolja fel. Ez a jelzés csupán a megfogalmazás eredetét és a szerzői jogokat jelzi, nem szolgál a cikkben szereplő információk forrásmegjelöléseként.