Gyártó metódus programtervezési minta
A gyártó metódus a szoftverfejlesztésben használatos létrehozási programtervezési minta.

Ezzel a programtervezési mintával kiváltható a kódban elhelyezett számos ugyanolyan példányosító utasítás. A gyártófüggvények neve magyar nyelvű kódban gyakran a „Készít”, angol nyelvű kódban a „Create”, „Make” vagy „Do” szóval kezdődik. A gyártófüggvény a nevében megadott osztály egy példányát adja vissza, például a „készítKocka” egy kockát, a „készítHáromszög” egy háromszöget. Ez azért előnyösebb, mint – C# nyelven – a new Kocka() vagy a new Háromszög() konstruktor hívás, mert így a létrehozás algoritmusát egységbe tudjuk zárni. Továbbá emelhetjük a termék absztrakciós szintjét, vagy elrejthetünk olyan információkat a kliens elől, amelyekre csak az objektum létrehozása miatt lenne szüksége. Így, ha a gyártás folyamata változik, csak egy helyen szükséges módosítani a kódot. Maga a gyártás folyamata ritkán változik, a tárgya annál gyakrabban, ezért ezt az OCP elvnek megfelelően a gyermek osztály dönti el.

Tehát az ősosztályban elhelyezett gyártómetódus írja le a gyártás algoritmusát, a gyermek osztály pedig eldönti, hogy mit kell gyártani. Ennek érdekében az algoritmus háromféle lépést tartalmazhat:

 A gyártás közös lépései: Az ősosztályban elhelyezett konkrét metódusok, általában nem virtuálisak, illetve Java nyelven final metódusok.
 A gyártás kötelező változó lépései. Ezek az ősosztályban elhelyezett absztrakt metódusok, amiket a gyermek felülír, amikor eldönti, mit kell gyártani. A gyermek osztályok itt hívják meg a termék konstruktorát.
 A gyártás opcionális lépései: Hook metódusok az ősosztályban, tehát a metódus csak egy üres törzzsel rendelkezik. Ezeket az OCP elv megszegése nélkül felül lehet írni az opcionális lépések kifejtéséhez.

A gyártó metódusra szemlélete példa a Microsoft Office alkalmazásaiban található Új menüpont, amely minden alkalmazásban létrehoz egy új dokumentumot és megnyitja. A megnyitás egyforma, de a létrehozás különböző. A szövegszerkesztő egy üres szöveges dokumentumot, a táblázatkezelő program esetén egy üres munkafüzetet hoz létre.

Az absztrakt ősosztály és a gyermek osztályai IOC (inversion of control, kontroll megfordítása) viszonyban állnak, nem a gyermek hívja az ősosztály metódusait, hanem fordítva. Ez úgy érhető el, hogy a gyártófüggvény absztrakt, illetve virtuális metódusokat hív. Ha a gyermek osztály példányán keresztül hívjuk meg a gyártófüggvényt, akkor a késői kötés miatt ezen metódusok helyett az őket felülíró gyermekbéli metódusok fognak lefutni.

Példa
A példa egy labirintusjáték, ami tartalmaz normál és elvarázsolt szobákat. A program létre tud hozni normál és elvarázsolt labirintusokat is. A játék szerkezete:

A Room a termékek (MagicRoom, OrdinaryRoom) közös általánosítása. A MazeGame egy absztrakt gyártó metódust tartalmaz, ami ilyen terméket gyárt. A MagicRoom és az OrdinaryRoom implementálják a megfelelő termékeket, míg a MagicMazeGame és az OrdinaryMazeGame a MazeGame gyerekeiként az ott deklarált gyártó metódust valósítják meg. Ezzel átveszik a hívót a konkrét osztályok implementációjából. Ezzel feleslegessé válik a new operátor, lehetővé válik a nyílt/zárt elv alkalmazása, és a végtermék rugalmasabban viselkedik a futásidejű változásokkal szemben.

Példakódok

Java
Az alábbi Java kódok a fenti labirintus (MazeGame) részleteit mutatják be. A normál szobákból csak a szomszéd szobákba lehet átmenni, míg az elvarázsolt szobákból véletlenszerűen lehet teleportálni. A MazeGame ezek közös általánosítását, a Room-okat használja, de a pontos megvalósítást utódaira hagyja.

public abstract class MazeGame {
    private final List<Room> rooms = new ArrayList<>();

    public MazeGame() {
        Room room1 = makeRoom();
        Room room2 = makeRoom();
        room1.connect(room2);
        rooms.add(room1);
        rooms.add(room2);
    }

    abstract protected Room makeRoom();
}

A fenti kódszakaszban a MazeGame konstruktora sablonfüggvényként van megvalósítva, és közös logikát foglal magába. Hivatkozik a makeRoom gyártó metódusra, ami magába foglalja a szobák létrehozását, így más szobák használhatók alosztályban. Egy másik játék metódushoz elég felülírni a makeRoom metódust:

public class MagicMazeGame extends MazeGame {
    @Override
    protected Room makeRoom() {
        return new MagicRoom();
    }
}

public class OrdinaryMazeGame extends MazeGame {
    @Override
    protected Room makeRoom() {
        return new OrdinaryRoom();
    }
}

MazeGame ordinaryGame = new OrdinaryMazeGame();
MazeGame magicGame = new MagicMazeGame();

PHP
Az alábbi PHP példa azt mutatja, hogy a termékek a leszármazás helyett meg is valósíthatnak egy interfészt, a gyártó metódus pedig publikus lehet, és a kliens közvetlenül is hívhatja:

/* Factory and car interfaces */

interface CarFactory
{
    public function makeCar();
}

interface Car
{
    public function getType();
}

/* Concrete implementations of the factory and car */

class SedanFactory implements CarFactory
{
    public function makeCar()
    {
        return new Sedan();
    }
}

class Sedan implements Car
{
    public function getType()
    {
        return 'Sedan';
    }
}

/* Client */

$factory = new SedanFactory();
$car = $factory->makeCar();
print $car->getType();

C#
using System;
namespace Factory_Method {
	abstract class MinositesGyar {
		public Minosites createMinosites() {
			// itt a gyártás előtt lehet ezt-azt csinálni, pl. logolni
			return Minosit();
		}
		public abstract Minosites Minosit();
	}
	class KonkretMinositesGyar1: MinositesGyar {
		public override Minosites Minosit() {
			return new A_Minosites();
		}
	}
	class KonkretMinositesGyar2: MinositesGyar {
		public override Minosites Minosit() {
			return new B_Minosites();
		}
	}
	interface Minosites {
		void Minosit();
	}
	class A_Minosites: Minosites {
		public void Minosit() {
			Console.WriteLine("A-minősítésben részesül!");
		}
	}
	class B_Minosites: Minosites {
		public void Minosit() {
			Console.WriteLine("B-minősítésben részesül!");
		}
	}
	class Program {
		static void Main(string[] args) {
			MinositesGyar[] minosito = new MinositesGyar[2];
			minosito[0] = new KonkretMinositesGyar1();
			minosito[1] = new KonkretMinositesGyar2();
			foreach(MinositesGyar m in minosito) {
				Minosites min = m.createMinosites();
				min.Minosit();
			}
			Console.ReadLine();
		}
	}
}

Felhasználása
 Az ADO.NET IDbCommand.CreateParameter tartalmaz példát a gyártó metódusra a párhuzamos osztályhierarchiák összekapcsolására.
 A Qt QMainWindow::createPopupMenu  keretrendszer gyártó metódust definiál, amit az alkalmazás kód felülírhat.
 A Java nyelv több gyárt metódust is nyújt, például a javax.xml.parsers csomagban, konkrétan pélédául javax.xml.parsers.DocumentBuilderFactory és javax.xml.parsers.SAXParserFactory.

Jegyzetek

Források

Fordítás

Programtervezési minták
C Sharp-kódpéldák
Java-kódpéldák
A gyártó metódus a szoftverfejlesztésben használatos létrehozási programtervezési minta . Ezzel a programtervezési mintával kiváltható a kódban elhelyezett számos ugyanolyan példányosító utasítás . A gyártófüggvények neve magyar nyelvű kódban gyakran a „ Készít” , angol nyelvű kódban a „ Create” , „ Make” vagy „ Do” szóval kezdődik . A gyártófüggvény a nevében megadott osztály egy példányát adja vissza , például a „ készítKocka” egy kockát , a „ készítHáromszög” egy háromszöget . Ez azért előnyösebb , mint – C # nyelven – a new Kocka ( ) vagy a new Háromszög ( ) konstruktor hívás , mert így a létrehozás algoritmusát egységbe tudjuk zárni . Továbbá emelhetjük a termék absztrakciós szintjét , vagy elrejthetünk olyan információkat a kliens elől , amelyekre csak az objektum létrehozása miatt lenne szüksége . Így , ha a gyártás folyamata változik , csak egy helyen szükséges módosítani a kódot . Maga a gyártás folyamata ritkán változik , a tárgya annál gyakrabban , ezért ezt az OCP elvnek megfelelően a gyermek osztály dönti el . Tehát az ősosztályban elhelyezett gyártómetódus írja le a gyártás algoritmusát , a gyermek osztály pedig eldönti , hogy mit kell gyártani . Ennek érdekében az algoritmus háromféle lépést tartalmazhat : A gyártás közös lépései : Az ősosztályban elhelyezett konkrét metódusok , általában nem virtuálisak , illetve Java nyelven final metódusok . A gyártás kötelező változó lépései . Ezek az ősosztályban elhelyezett absztrakt metódusok , amiket a gyermek felülír , amikor eldönti , mit kell gyártani . A gyermek osztályok itt hívják meg a termék konstruktorát . A gyártás opcionális lépései : Hook metódusok az ősosztályban , tehát a metódus csak egy üres törzzsel rendelkezik . Ezeket az OCP elv megszegése nélkül felül lehet írni az opcionális lépések kifejtéséhez . A gyártó metódusra szemlélete példa a Microsoft Office alkalmazásaiban található Új menüpont , amely minden alkalmazásban létrehoz egy új dokumentumot és megnyitja . A megnyitás egyforma , de a létrehozás különböző . A szövegszerkesztő egy üres szöveges dokumentumot , a táblázatkezelő program esetén egy üres munkafüzetet hoz létre . Az absztrakt ősosztály és a gyermek osztályai IOC ( inversion of control , kontroll megfordítása ) viszonyban állnak , nem a gyermek hívja az ősosztály metódusait , hanem fordítva . Ez úgy érhető el , hogy a gyártófüggvény absztrakt , illetve virtuális metódusokat hív . Ha a gyermek osztály példányán keresztül hívjuk meg a gyártófüggvényt , akkor a késői kötés miatt ezen metódusok helyett az őket felülíró gyermekbéli metódusok fognak lefutni . Példa A példa egy labirintusjáték , ami tartalmaz normál és elvarázsolt szobákat . A program létre tud hozni normál és elvarázsolt labirintusokat is . A játék szerkezete : A Room a termékek ( MagicRoom , OrdinaryRoom ) közös általánosítása . A MazeGame egy absztrakt gyártó metódust tartalmaz , ami ilyen terméket gyárt . A MagicRoom és az OrdinaryRoom implementálják a megfelelő termékeket , míg a MagicMazeGame és az OrdinaryMazeGame a MazeGame gyerekeiként az ott deklarált gyártó metódust valósítják meg . Ezzel átveszik a hívót a konkrét osztályok implementációjából . Ezzel feleslegessé válik a new operátor , lehetővé válik a nyílt/zárt elv alkalmazása , és a végtermék rugalmasabban viselkedik a futásidejű változásokkal szemben . Példakódok Java Az alábbi Java kódok a fenti labirintus ( MazeGame ) részleteit mutatják be . A normál szobákból csak a szomszéd szobákba lehet átmenni , míg az elvarázsolt szobákból véletlenszerűen lehet teleportálni . A MazeGame ezek közös általánosítását , a Room-okat használja , de a pontos megvalósítást utódaira hagyja . public abstract class MazeGame { private final List<Room> rooms = new ArrayList<> ( ) ; public MazeGame ( ) { Room room1 = makeRoom ( ) ; Room room2 = makeRoom ( ) ; room1.connect ( room2 ) ; rooms.add ( room1 ) ; rooms.add ( room2 ) ; } abstract protected Room makeRoom ( ) ; } A fenti kódszakaszban a MazeGame konstruktora sablonfüggvényként van megvalósítva , és közös logikát foglal magába . Hivatkozik a makeRoom gyártó metódusra , ami magába foglalja a szobák létrehozását , így más szobák használhatók alosztályban . Egy másik játék metódushoz elég felülírni a makeRoom metódust : public class MagicMazeGame extends MazeGame { @ Override protected Room makeRoom ( ) { return new MagicRoom ( ) ; } } public class OrdinaryMazeGame extends MazeGame { @ Override protected Room makeRoom ( ) { return new OrdinaryRoom ( ) ; } } MazeGame ordinaryGame = new OrdinaryMazeGame ( ) ; MazeGame magicGame = new MagicMazeGame ( ) ; PHP Az alábbi PHP példa azt mutatja , hogy a termékek a leszármazás helyett meg is valósíthatnak egy interfészt , a gyártó metódus pedig publikus lehet , és a kliens közvetlenül is hívhatja : / * Factory and car interfaces * / interface CarFactory { public function makeCar ( ) ; } interface Car { public function getType ( ) ; } / * Concrete implementations of the factory and car * / class SedanFactory implements CarFactory { public function makeCar ( ) { return new Sedan ( ) ; } } class Sedan implements Car { public function getType ( ) { return 'Sedan' ; } } / * Client * / $factory = new SedanFactory ( ) ; $car = $factory->makeCar ( ) ; print $car->getType ( ) ; C # using System ; namespace Factory_Method { abstract class MinositesGyar { public Minosites createMinosites ( ) { / / itt a gyártás előtt lehet ezt-azt csinálni , pl. logolni return Minosit ( ) ; } public abstract Minosites Minosit ( ) ; } class KonkretMinositesGyar1 : MinositesGyar { public override Minosites Minosit ( ) { return new A_Minosites ( ) ; } } class KonkretMinositesGyar2 : MinositesGyar { public override Minosites Minosit ( ) { return new B_Minosites ( ) ; } } interface Minosites { void Minosit ( ) ; } class A_Minosites : Minosites { public void Minosit ( ) { Console.WriteLine ( " A-minősítésben részesül ! " ) ; } } class B_Minosites : Minosites { public void Minosit ( ) { Console.WriteLine ( "B-minősítésben részesül ! " ) ; } } class Program { static void Main( string [ ] args ) { MinositesGyar [ ] minosito = new MinositesGyar [ 2 ] ; minosito [ 0 ] = new KonkretMinositesGyar1 ( ) ; minosito [ 1 ] = new KonkretMinositesGyar2 ( ) ; foreach ( MinositesGyar m in minosito ) { Minosites min = m.createMinosites ( ) ; min.Minosit ( ) ; } Console.ReadLine ( ) ; } } } Felhasználása Az ADO.NET IDbCommand.CreateParameter tartalmaz példát a gyártó metódusra a párhuzamos osztályhierarchiák összekapcsolására . A Qt QMainWindow : : createPopupMenu keretrendszer gyártó metódust definiál , amit az alkalmazás kód felülírhat . A Java nyelv több gyárt metódust is nyújt , például a javax.xml.parsers csomagban , konkrétan pélédául javax.xml.parsers.DocumentBuilderFactory és javax.xml.parsers.SAXParserFactory . Jegyzetek Források Fordítás Programtervezési minták C Sharp-kódpéldák Java-kódpéldák