Absztrakt gyár programtervezési minta
Az Absztrakt gyár (angolul Abstract factory) programtervezési minta módot nyújt arra, hogy egységbe zárjuk közös témához kapcsolódó egyedi gyártó metódusok egy csoportját anélkül, hogy specifikálnák azok konkrét osztályait.
Normál használatban, a kliens szoftver létrehozza az absztrakt gyár egy konkrét implementációját, és aztán a gyár általános interfészét használja a témához kapcsolódó konkrét objektumok létrehozásához. A kliens nem tudja (vagy nem törődik vele), milyen konkrét objektumokat kap ezekből a belső gyárakból, mivel csak a termékeik általános interfészét használja. Ez a tervezési minta szétválasztja egymástól objektumok egy csoportjának implementációját azok általános használatától és objektum összetételre hagyatkozik, mivel az objektumok létrehozása olyan metódusokban van implementálva, amik a gyár interfészén vannak ismertté téve számára.
Egy példa az absztrakt gyár mintára, egy DokumentumLétrehozó nevű absztrakt osztály lehetne, ami interfészt nyújt többféle termék létrehozásához (pl.készítsLevelet() és készítsÖsszefoglalót()). A rendszerben bármennyi DokumentumLétrehozó osztályból származtatott konkrét gyár-változat lehet, mint például DíszesDokumentumLétrehozó vagy ModernDokumentumLétrehozó, mindegyikük különböző implementációval a készítsLevelet() és készítsÖsszefoglalót() metódusokra, amik elkészítik majd a megfelelő objektumokat mint például a DíszesLevél vagy a ModernÖsszefoglaló. Ezeknek a termékeknek mindegyike egy-egy egyszerű absztrakt osztályból van származtatva, mint például a Levél vagy az Összefoglaló, amik ismertek a kliens számára. A kliens kódja egy a témának megfelelő példányt fog kapni a DokumentumLétrehozó osztály egy származtatott konkrét osztályából, és annak a gyártó metódusait hívja majd meg. Az eredményül kapott objektumok mindegyike, ezen DokumentumLétrehozó osztály-implementáció által kerül majd legyártásra, amik megfelelnek majd a közös témának (például mindannyian „Díszes” vagy „Modern” objektumok lesznek). A kliensnek csak annyit kell tudnia, hogy hogyan kezelje az absztrakt Levél vagy Összefoglaló osztályokat, nem kell ismernie a specifikus változatokat, amiket a konkrét gyártól kapott.

Egy gyár, egy konkrét osztály helye a kódban, ahol az objektumok létrejönnek. Az absztrakt gyár minta használatának szándéka arra irányul, hogy elszigetelje egymástól az objektumok létrehozását azok használatától, és hogy egymással összefüggő objektumok családjait hozza létre anélkül, hogy azok konkrét osztályaitól függene. Ez lehetővé teszi új származtatott típusok bevezetését, anélkül, hogy az ős osztályokat használó kódot meg kellene változtatni.

Ennek a mintának a használata, lehetővé teszi egy rendszerben a konkrét típus implementációk kicserélését (még akár futásidőben is) anélkül, hogy az őket használó kódot módosítanánk. Mindazonáltal ennek a mintának (és a hasonló programtervezési mintáknak) a használata, szükségtelen komplexitást okozhat, és plusz munkát igényelhet a kezdeti kódkészítésben. Továbbá az absztrakció és a szétválasztás magasabb szintje olyan rendszert eredményezhet, amiben nehezebb a hibakeresés és a karbantartás.

Definíció 
Az Absztrakt gyár minta lényege, hogy „Interfészt adjon ahhoz, hogy egymással összefüggő objektumok családjait hozzuk létre anélkül, hogy specifikálnánk a konkrét osztályaikat.”.

Használat 
A gyár határozza meg a létrehozásra kerülő objektum tényleges konkrét típusát, és a gyár az a hely ahol az objektum ténylegesen létrejön (például a C++ nyelven, a new művelettel). Mindazonáltal, a gyár csak egy absztrakt mutatót (pointert) ad vissza, ami a létrehozott konkrét objektumra mutat.

Ez elszigeteli a klienst az objektum létrehozástól azáltal, hogy a kliensnek meg kell kérnie egy gyár objektumot, hogy készítse el az általa kívánt absztrakt típust és adjon vissza számára egy absztrakt mutatót az objektumra.

Mivel a gyár csak egy absztrakt mutatót (pointert) ad vissza, a kliens kód (ami az objektumot kérte a gyártól) nem ismeri az éppen létrehozott objektum aktuális, konkrét típusát. Mindazonáltal az absztrakt gyár ismeri a konkrét objektum típusát (ennélfogva a konkrét gyárat is); például az absztrakt gyár beolvashatja ezeket az adatokat egy konfigurációs fájlból. A kliensnek így nem kell típust specifikálnia, mivel az már megadásra került a konfigurációs fájlban. Részleteiben ez a következőt jelenti:

 A kliens kódnak semmiféle tudomása nincs a konkrét típusról, nem szükséges meghivatkoznia vagy tartalmaznia semmilyen ezzel kapcsolatos header fájlt vagy osztály deklarációt. A kliens kód csak az absztrakt típussal dolgozik. A konkrét típusnak megfelelő objektumok ténylegesen a gyár által kerülnek létrehozásra, de a kliens kód képes használni ezeket az absztrakt interfészükön keresztül (kizárólag ezen keresztül, mivel csak ezt ismeri).
 Új konkrét típusok hozzáadása (használata) a kliens kód módosításával történik úgy, hogy azok egy másik gyárat használjanak mint eddig, amely módosítás jellemzően egyetlen sort érint, egyetlen fájlban. A másik (módosított) gyár aztán eltérő konkrét típus hoz majd létre, de még mindig ugyanolyan absztrakt típusra irányuló mutatót ad vissza, mint annak előtte — ezáltal elszigeteli a kliens kódját a változástól. Ez jelentősen egyszerűbb, mint módosítani a kliens kódját arra, hogy újfajta típust hozzon létre, ami változtatást kívánna meg minden helyen a kódban, ahol az újfajta objektum létrehozásra kerül (ami mellett biztosítani kellene azt is, hogy az összes ilyen kód-hely tudomással rendelkezzen az újfajta konkrét típusról, például azzal, hogy a forráskódokban mindenhol meghivatkozzuk az újfajta osztály header fájlját). Ha minden gyártó objektum globálisan tárolva van egy Egyke (singleton) objektumban, és az összes kliens kód ezen keresztül éri el a megfelelő gyárat az objektum létrehozáshoz, akkor a gyárak (ezáltal a gyártott konkrét típusok) megváltoztatása ennek az Egyke objektumnak a megváltoztatására egyszerűsödik.

Felépítése

Rational Osztály Diagram 

A createButton függvény a GuiFactory interfészben Button típusú objektumokat ad vissza. Az, hogy a Button objektumnak milyen konkrét implementációja kerül visszaadásra, a GuiFactory osztály implementációján múlik, ami a függvényhívást kezeli.

UML Osztály Diagram

Lepus3 Diagram (jelmagyarázat)

Pszeudokód 
A kód egy gombot (Button) készít, amely Windows vagy Mac OS X stílusú lehet, attól függően, hogy melyik gyárat használjuk. Vegyük észre, hogy az alkalmazásnak (Application) semmilyen tudomása nincs arról, hogy milyen „GuiFactory” gyár van számára megadva (mi a konkrét implementációja), mint ahogy arról sem, hogy az konkrétan milyen gombot (Button) gyárt.

 interface Button is
   method paint()
 
 interface GUIFactory is
   method createButton()
       output:  a button
 
 class WinFactory implementing GUIFactory is
   method createButton() is
       output:  a Windows button
     Return a new WinButton
 
 class OSXFactory implementing GUIFactory is
   method createButton() is
       output:  an OS X button
     Return a new OSXButton
 
 class WinButton implementing Button is
   method paint() is
     Render a button in a Windows style
 
 class OSXButton implementing Button is
   method paint() is
     Render a button in a Mac OS X style
 
 class Application is
   constructor Application(factory) is
       input:  the GUIFactory factory used to create buttons
     Button button := factory.createButton()
     button.paint()
 
 Read the configuration file
 If the OS specified in the configuration file is Windows, then
   Construct a WinFactory
   Construct an Application with WinFactory
 else
   Construct an OSXFactory
   Construct an Application with OSXFactory

C# példa 
Az Absztrakt gyár az alap Gyár minta bővítése. Gyár interfészeket nyújt egymással összetartozó osztályok gyártásához. Más szavakkal, interfészeket deklarálok a Gyárakhoz, amiket aztán hasonló módon használok mint az alap Gyár mintánál.
/*IVSR:Abstract factory pattern*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DesignPatterns.AbstractFactory
{
    public class GenericFactory<T> 
        where T : new()
    {
        public T CreateObject()
        {
            return new T();
        }
    }

    public abstract class CarFactory
    {
        public abstract SportsCar CreateSportsCar();
        public abstract FamilyCar CreateFamilyCar();
    }
    
    public abstract class FamilyCar
    {
        public abstract void Speed(SportsCar abstractSportsCar);
    }

    public abstract class SportsCar
    {
    }

    public class MercedesFactory : CarFactory
    {
        public override SportsCar CreateSportsCar()
        {
            return new MercedesSportsCar();
        }

        public override FamilyCar CreateFamilyCar()
        {
            return new MercedesFamilyCar();
        }
    }

     
    class MercedesSportsCar : SportsCar
    {
    }

    class MercedesFamilyCar : FamilyCar
    {
        public override void Speed(SportsCar abstractSportsCar)
        {
            Console.WriteLine(GetType().Name + " is slower than "
                + abstractSportsCar.GetType().Name);
        }
    }

    public class Driver
    {
        private CarFactory _carFactory;
        private SportsCar _sportsCar;
        private FamilyCar _familyCar;

        public Driver(CarFactory carFactory)
        {
            _carFactory = carFactory;
            _sportsCar = _carFactory.CreateSportsCar();
            _familyCar = _carFactory.CreateFamilyCar();
        }

        public CarFactory CarFactory
        {
            get { return _carFactory; }
            set { _carFactory = value; }
        }

        public SportsCar SportsCar
        {
            get { return _sportsCar; }
        }

        public FamilyCar FamilyCar
        {
            get { return _familyCar; }
        }

        public void CompareSpeed()
        {
            FamilyCar.Speed(SportsCar);
        }
    }
}

A gyártó metódusok szintén egy közös interfész alapján vannak implementálva, melyek mindegyike objektumokat ad vissza.
    //IVSR: Abstract factory using common interface
    public interface IPeopleFactory
    {
        IPeople GetPeople();
    }

    public class VillagersFactory : IPeopleFactory
    {
        public IPeople GetPeople()
        {
            return new Villagers();
        }
    }

    public interface IProductFactory
    {
        IProduct GetProduct();
    }

    public class AppleFactory : IProductFactory
    {
        public IProduct GetProduct()
        {
            return new IPhone();
        }
    }

    public abstract class AbstractFactory
    {
        public abstract IPeopleFactory GetPeopleFactory();
        public abstract IProductFactory GetProductFactory();
    }

    public class ConcreteFactory : AbstractFactory
    {
        public override IPeopleFactory GetPeopleFactory()
        {
            return new VillagersFactory ();
        }

        public override IProductFactory GetProductFactory()
        {
            return new AppleFactory ();
        }
    }

Kapcsolódó szócikkek 
 Konkrét osztály
 Programtervezési minta
 Gyártó metódus programtervezési minta
 Objektum létrehozás

Jegyzetek

Fordítás 

Programtervezési minták
C Sharp-kódpéldák
Az Absztrakt gyár ( angolul Abstract factory ) programtervezési minta módot nyújt arra , hogy egységbe zárjuk közös témához kapcsolódó egyedi gyártó metódusok egy csoportját anélkül , hogy specifikálnák azok konkrét osztályait . Normál használatban , a kliens szoftver létrehozza az absztrakt gyár egy konkrét implementációját , és aztán a gyár általános interfészét használja a témához kapcsolódó konkrét objektumok létrehozásához . A kliens nem tudja ( vagy nem törődik vele ) , milyen konkrét objektumokat kap ezekből a belső gyárakból , mivel csak a termékeik általános interfészét használja . Ez a tervezési minta szétválasztja egymástól objektumok egy csoportjának implementációját azok általános használatától és objektum összetételre hagyatkozik , mivel az objektumok létrehozása olyan metódusokban van implementálva , amik a gyár interfészén vannak ismertté téve számára . Egy példa az absztrakt gyár mintára , egy DokumentumLétrehozó nevű absztrakt osztály lehetne , ami interfészt nyújt többféle termék létrehozásához ( pl.készítsLevelet ( ) és készítsÖsszefoglalót ( ) ) . A rendszerben bármennyi DokumentumLétrehozó osztályból származtatott konkrét gyár-változat lehet , mint például DíszesDokumentumLétrehozó vagy ModernDokumentumLétrehozó , mindegyikük különböző implementációval a készítsLevelet ( ) és készítsÖsszefoglalót ( ) metódusokra , amik elkészítik majd a megfelelő objektumokat mint például a DíszesLevél vagy a ModernÖsszefoglaló . Ezeknek a termékeknek mindegyike egy-egy egyszerű absztrakt osztályból van származtatva , mint például a Levél vagy az Összefoglaló , amik ismertek a kliens számára . A kliens kódja egy a témának megfelelő példányt fog kapni a DokumentumLétrehozó osztály egy származtatott konkrét osztályából , és annak a gyártó metódusait hívja majd meg . Az eredményül kapott objektumok mindegyike , ezen DokumentumLétrehozó osztály-implementáció által kerül majd legyártásra , amik megfelelnek majd a közös témának ( például mindannyian „ Díszes” vagy „ Modern” objektumok lesznek ) . A kliensnek csak annyit kell tudnia , hogy hogyan kezelje az absztrakt Levél vagy Összefoglaló osztályokat , nem kell ismernie a specifikus változatokat , amiket a konkrét gyártól kapott . Egy gyár , egy konkrét osztály helye a kódban , ahol az objektumok létrejönnek . Az absztrakt gyár minta használatának szándéka arra irányul , hogy elszigetelje egymástól az objektumok létrehozását azok használatától , és hogy egymással összefüggő objektumok családjait hozza létre anélkül , hogy azok konkrét osztályaitól függene . Ez lehetővé teszi új származtatott típusok bevezetését , anélkül , hogy az ős osztályokat használó kódot meg kellene változtatni . Ennek a mintának a használata , lehetővé teszi egy rendszerben a konkrét típus implementációk kicserélését ( még akár futásidőben is ) anélkül , hogy az őket használó kódot módosítanánk . Mindazonáltal ennek a mintának ( és a hasonló programtervezési mintáknak ) a használata , szükségtelen komplexitást okozhat , és plusz munkát igényelhet a kezdeti kódkészítésben . Továbbá az absztrakció és a szétválasztás magasabb szintje olyan rendszert eredményezhet , amiben nehezebb a hibakeresés és a karbantartás . Definíció Az Absztrakt gyár minta lényege , hogy „ Interfészt adjon ahhoz , hogy egymással összefüggő objektumok családjait hozzuk létre anélkül , hogy specifikálnánk a konkrét osztályaikat.” . Használat A gyár határozza meg a létrehozásra kerülő objektum tényleges konkrét típusát , és a gyár az a hely ahol az objektum ténylegesen létrejön ( például a C++ nyelven , a new művelettel ) . Mindazonáltal , a gyár csak egy absztrakt mutatót ( pointert ) ad vissza , ami a létrehozott konkrét objektumra mutat . Ez elszigeteli a klienst az objektum létrehozástól azáltal , hogy a kliensnek meg kell kérnie egy gyár objektumot , hogy készítse el az általa kívánt absztrakt típust és adjon vissza számára egy absztrakt mutatót az objektumra . Mivel a gyár csak egy absztrakt mutatót ( pointert ) ad vissza , a kliens kód ( ami az objektumot kérte a gyártól ) nem ismeri az éppen létrehozott objektum aktuális , konkrét típusát . Mindazonáltal az absztrakt gyár ismeri a konkrét objektum típusát ( ennélfogva a konkrét gyárat is ) ; például az absztrakt gyár beolvashatja ezeket az adatokat egy konfigurációs fájlból . A kliensnek így nem kell típust specifikálnia , mivel az már megadásra került a konfigurációs fájlban . Részleteiben ez a következőt jelenti : A kliens kódnak semmiféle tudomása nincs a konkrét típusról , nem szükséges meghivatkoznia vagy tartalmaznia semmilyen ezzel kapcsolatos header fájlt vagy osztály deklarációt . A kliens kód csak az absztrakt típussal dolgozik . A konkrét típusnak megfelelő objektumok ténylegesen a gyár által kerülnek létrehozásra , de a kliens kód képes használni ezeket az absztrakt interfészükön keresztül ( kizárólag ezen keresztül , mivel csak ezt ismeri ) . Új konkrét típusok hozzáadása ( használata ) a kliens kód módosításával történik úgy , hogy azok egy másik gyárat használjanak mint eddig , amely módosítás jellemzően egyetlen sort érint , egyetlen fájlban . A másik ( módosított ) gyár aztán eltérő konkrét típus hoz majd létre , de még mindig ugyanolyan absztrakt típusra irányuló mutatót ad vissza , mint annak előtte — ezáltal elszigeteli a kliens kódját a változástól . Ez jelentősen egyszerűbb , mint módosítani a kliens kódját arra , hogy újfajta típust hozzon létre , ami változtatást kívánna meg minden helyen a kódban , ahol az újfajta objektum létrehozásra kerül ( ami mellett biztosítani kellene azt is , hogy az összes ilyen kód-hely tudomással rendelkezzen az újfajta konkrét típusról , például azzal , hogy a forráskódokban mindenhol meghivatkozzuk az újfajta osztály header fájlját ) . Ha minden gyártó objektum globálisan tárolva van egy Egyke ( singleton ) objektumban , és az összes kliens kód ezen keresztül éri el a megfelelő gyárat az objektum létrehozáshoz , akkor a gyárak ( ezáltal a gyártott konkrét típusok ) megváltoztatása ennek az Egyke objektumnak a megváltoztatására egyszerűsödik . Felépítése Rational Osztály Diagram A createButton függvény a GuiFactory interfészben Button típusú objektumokat ad vissza . Az , hogy a Button objektumnak milyen konkrét implementációja kerül visszaadásra , a GuiFactory osztály implementációján múlik , ami a függvényhívást kezeli . UML Osztály Diagram Lepus3 Diagram ( jelmagyarázat ) Pszeudokód A kód egy gombot ( Button ) készít , amely Windows vagy Mac OS X stílusú lehet , attól függően , hogy melyik gyárat használjuk . Vegyük észre , hogy az alkalmazásnak ( Application ) semmilyen tudomása nincs arról , hogy milyen „ GuiFactory” gyár van számára megadva ( mi a konkrét implementációja ) , mint ahogy arról sem , hogy az konkrétan milyen gombot ( Button ) gyárt. interface Button is method paint ( ) interface GUIFactory is method createButton ( ) output : a button class WinFactory implementing GUIFactory is method createButton ( ) is output : a Windows button Return a new WinButton class OSXFactory implementing GUIFactory is method createButton ( ) is output : an OS X button Return a new OSXButton class WinButton implementing Button is method paint ( ) is Render a button in a Windows style class OSXButton implementing Button is method paint ( ) is Render a button in a Mac OS X style class Application is constructor Application ( factory ) is input : the GUIFactory factory used to create buttons Button button \:= factory.createButton ( ) button.paint ( ) Read the configuration file If the OS specified in the configuration file is Windows , then Construct a WinFactory Construct an Application with WinFactory else Construct an OSXFactory Construct an Application with OSXFactory C # példa Az Absztrakt gyár az alap Gyár minta bővítése . Gyár interfészeket nyújt egymással összetartozó osztályok gyártásához . Más szavakkal , interfészeket deklarálok a Gyárakhoz , amiket aztán hasonló módon használok mint az alap Gyár mintánál . /*IVSR: Abstract factory pattern * / using System ; using System.Collections.Generic ; using System.Linq ; using System.Text ; namespace DesignPatterns.AbstractFactory { public class GenericFactory<T> where T \ : new ( ) { public T CreateObject ( ) { return new T ( ) ; } } public abstract class CarFactory { public abstract SportsCar CreateSportsCar ( ) ; public abstract FamilyCar CreateFamilyCar ( ) ; } public abstract class FamilyCar { public abstract void Speed( SportsCar abstractSportsCar ) ; } public abstract class SportsCar { } public class MercedesFactory \ : CarFactory { public override SportsCar CreateSportsCar ( ) { return new MercedesSportsCar ( ) ; } public override FamilyCar CreateFamilyCar ( ) { return new MercedesFamilyCar ( ) ; } } class MercedesSportsCar \ : SportsCar { } class MercedesFamilyCar \ : FamilyCar { public override void Speed( SportsCar abstractSportsCar ) { Console.WriteLine ( GetType ( ) . Name + " is slower than " + abstractSportsCar.GetType ( ) .Name ) ; } } public class Driver { private CarFactory _carFactory ; private SportsCar _sportsCar ; private FamilyCar _familyCar ; public Driver( CarFactory carFactory ) { _carFactory = carFactory ; _sportsCar = _carFactory.CreateSportsCar ( ) ; _familyCar = _carFactory.CreateFamilyCar ( ) ; } public CarFactory CarFactory { get { return _carFactory ; } set { _carFactory = value ; } } public SportsCar SportsCar { get { return _sportsCar ; } } public FamilyCar FamilyCar { get { return _familyCar ; } } public void CompareSpeed ( ) { FamilyCar.Speed ( SportsCar ) ; } } } A gyártó metódusok szintén egy közös interfész alapján vannak implementálva , melyek mindegyike objektumokat ad vissza . //IVSR: Abstract factory using common interface public interface IPeopleFactory { IPeople GetPeople ( ) ; } public class VillagersFactory \ : IPeopleFactory { public IPeople GetPeople ( ) { return new Villagers ( ) ; } } public interface IProductFactory { IProduct GetProduct ( ) ; } public class AppleFactory \ : IProductFactory { public IProduct GetProduct ( ) { return new IPhone ( ) ; } } public abstract class AbstractFactory { public abstract IPeopleFactory GetPeopleFactory ( ) ; public abstract IProductFactory GetProductFactory ( ) ; } public class ConcreteFactory \ : AbstractFactory { public override IPeopleFactory GetPeopleFactory ( ) { return new VillagersFactory ( ) ; } public override IProductFactory GetProductFactory ( ) { return new AppleFactory ( ) ; } } Kapcsolódó szócikkek Konkrét osztály Programtervezési minta Gyártó metódus programtervezési minta Objektum létrehozás Jegyzetek Fordítás Programtervezési minták C Sharp-kódpéldák