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.[1]
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
[szerkesztés]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
[szerkesztés]Java
[szerkesztés]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
[szerkesztés]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#
[szerkesztés]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
[szerkesztés]- 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 Archiválva 2015. július 19-i dátummal a Wayback Machine-ben 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[halott link] csomagban, konkrétan például javax.xml.parsers.DocumentBuilderFactory és javax.xml.parsers.SAXParserFactory.
Jegyzetek
[szerkesztés]- ↑ (2004) „Head First Design Patterns” (paperback) 1, 162. o, Kiadó: O'REILLY. (Hozzáférés: 2012. szeptember 12.)
Források
[szerkesztés]- Dr. Kusper Gábor és Dr. Radványi Tibor: Jegyzet a projekt labor című tárgyhoz (PDF). Eszterházy Károly Főiskola Matematikai és Informatikai Intézet. (Hozzáférés: 2015. április 6.)
- Refactoring: Improving the Design of Existing Code. Addison-Wesley (1999. június 1.). ISBN 0-201-48567-2
- Gamma, Erich; Helm, Richard; Johnson, Ralph; Vlissides, John. Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley (1994). ISBN 0-201-63361-2
- Cox, Brad J.;. Object-oriented programming: an evolutionary approach. Addison-Wesley (1986). ISBN 978-0-201-10393-9
- Cohen, Tal (2007). „Better Construction with Factories” (PDF). Journal of Object Technology, Kiadó: Bertrand Meyer. (Hozzáférés: 2007. március 12.)
Fordítás
[szerkesztés]Ez a szócikk részben vagy egészben a Factory method 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.