Egyke programtervezési minta

A Wikipédiából, a szabad enciklopédiából
Ugrás a navigációhoz Ugrás a kereséshez
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 legyen 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]

Sokan erősen kritizálják az egyke mintát, és antimintának tekintik, mivel szükségtelen korlátozásokat és globális állapotokat helyez el az alkalmazásban, illetve csökkenti a tesztelhetőséget.[2][3][4]

Felhasználása[szerkesztés]

Egykét csak akkor érdemes használni, ha több példány egyidejű létezése a rendszer rendellenes működését vagy összeomlását okozhatja. A homlokzatok például gyakran egykék. Az absztrakt gyártó, az építő és a prototípus minták implementációja is gyakran épül az egyke mintára.

A globális változókkal szemben gyakran az egykéket részesítik előnyben, mivel nem szennyezik a névteret szükségtelen változókkal, és 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[szerkesztés]

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

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

Ezt rendszerint így érik el:

  • minden konstruktor privát
  • a példány referenciája egy osztálymetóduson keresztül érhető el

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. Egyszerű példa Java nyelven:

public final class Egyke {
    private static final Egyke PELDANY = new Egyke();

    private Egyke() {}

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

Javában gyakran használnak egyelemű enum-ot is, mert így maga a Java környezet biztosítja a példány egyediségét:

public enum Egyke {
    PELDANY {
        // ...
    }
}

Az egyke használható lusta inicializációval. Ekkor a példány csak akkor jön létre, amikor az osztálymetódus először meghívódik. Ha ezt párhuzamos környezetben használják, akkor biztosítani kell, hogy ne legyen versenyhelyzet, különben több szál is létrehozhat egy-egy példányt. Ehhez teljes szinkronizálás helyett (a teljesítmény növelése céljából) gyakran használnak duplán ellenőrzött lockolást, ami azonban önmagában elégtelen, mivel az ellenőrzés pillanatában a példány inicializációja még bejezetlen lehet, annak ellenére, hogy a változó értéke már nem null.[5] A következő Java példa egy segédváltozót használ az inicializált állapot ellenőrzésére:

public final class Egyke {
    
    private static volatile boolean letrehozva = false;
    private static volatile Egyke peldany = null;

    private Egyke() {}

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

Egyszerű egyke példakód C#-ban[szerkesztés]

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[szerkesztés]

Fordítás[szerkeszté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 jelzi, nem szolgál a cikkben szereplő információk forrásmegjelöléseként.