Szia! Ma folytatjuk a tervezési minták tanulmányozását, és megvitatjuk a gyári módszer mintáját.
Megtudhatja, mi ez, és milyen feladatokra alkalmas ez a minta. Ezt a tervezési mintát a gyakorlatban megvizsgáljuk, és megvizsgáljuk a szerkezetét. Annak érdekében, hogy minden világos legyen, meg kell értenie a következő témákat:
Milyen következtetéseket vonhatunk le?
A fenti diagram a gyári módszer mintájának általános felépítését mutatja. Mi más fontos itt?

- Öröklés Java nyelven.
- Absztrakt metódusok és osztályok a Java nyelven
Milyen problémát old meg a gyári módszer?
Minden gyári tervezési mintának kétféle résztvevője van: alkotók (maguk a gyárak) és termékek (a gyárak által létrehozott tárgyak). Képzeljük el a következő helyzetet: van egy gyárunk, amely CodeGym márkájú autókat gyárt. Tudja, hogyan hozhat létre különféle karosszériájú autómodelleket:- szedánok
- kombi kocsik
- kupék
- CodeGym szedánok
- CodeGym kombi
- CodeGym kupék
- OneAuto szedánok
- OneAuto kombi
- OneAuto kupék
Egy kicsit a gyári mintáról
Hadd emlékeztesselek arra, hogy korábban építettünk egy kis virtuális kávézót. Egy egyszerű gyár segítségével megtanultuk, hogyan készítsünk különböző kávéfajtákat. Ma ezt a példát dolgozzuk át. Emlékezzünk vissza, hogyan nézett ki kávézónk, egyszerű gyárával. Kávéórát tartottunk:
public class Coffee {
public void grindCoffee(){
// Grind the coffee
}
public void makeCoffee(){
// Brew the coffee
}
public void pourIntoCup(){
// Pour into a cup
}
}
És számos gyermekosztály, amelyek megfelelnek a gyárunk által gyártott kávéfajtáknak:
public class Americano extends Coffee {}
public class Cappuccino extends Coffee {}
public class CaffeLatte extends Coffee {}
public class Espresso extends Coffee {}
Létrehoztunk egy listát, hogy megkönnyítsük a rendeléseket:
public enum CoffeeType {
ESPRESSO,
AMERICANO,
CAFFE_LATTE,
CAPPUCCINO
}
Maga a kávégyár így nézett ki:
public class SimpleCoffeeFactory {
public Coffee createCoffee(CoffeeType type) {
Coffee coffee = null;
switch (type) {
case AMERICANO:
coffee = new Americano();
break;
case ESPRESSO:
coffee = new Espresso();
break;
case CAPPUCCINO:
coffee = new Cappuccino();
break;
case CAFFE_LATTE:
coffee = new CaffeLatte();
break;
}
return coffee;
}
}
És végül maga a kávézó így nézett ki:
public class CoffeeShop {
private final SimpleCoffeeFactory coffeeFactory;
public CoffeeShop(SimpleCoffeeFactory coffeeFactory) {
this.coffeeFactory = coffeeFactory;
}
public Coffee orderCoffee(CoffeeType type) {
Coffee coffee = coffeeFactory.createCoffee(type);
coffee.grindCoffee();
coffee.makeCoffee();
coffee.pourIntoCup();
System.out.println("Here's your coffee! Thanks! Come again!");
return coffee;
}
}
Egy egyszerű gyár korszerűsítése
A kávézónk nagyon jól működik. Olyannyira, hogy fontolgatjuk a bővítést. Néhány új helyszínt szeretnénk nyitni. Merészek és vállalkozó szelleműek vagyunk, így nem fogunk unalmas kávéházakat kirángatni. Azt akarjuk, hogy minden üzletben különleges fordulat legyen. Ennek megfelelően kezdetben két helyszínt nyitunk meg: egy olasz és egy amerikai. Ezek a változások nemcsak a belső kialakítást érintik, hanem a kínált italokat is:- az olasz kávézóban kizárólag olasz kávémárkákat használunk, speciális őrléssel és pörköléssel.
- az amerikai helyszínen nagyobb adagok lesznek, és minden rendelésnél mályvacukrot szolgálunk fel.
public class Americano extends Coffee {}
public class Cappuccino extends Coffee {}
public class CaffeLatte extends Coffee {}
public class Espresso extends Coffee {}
De most 8 lesz:
public class ItalianStyleAmericano extends Coffee {}
public class ItalianStyleCappucino extends Coffee {}
public class ItalianStyleCaffeLatte extends Coffee {}
public class ItalianStyleEspresso extends Coffee {}
public class AmericanStyleAmericano extends Coffee {}
public class AmericanStyleCappucino extends Coffee {}
public class AmericanStyleCaffeLatte extends Coffee {}
public class AmericanStyleEspresso extends Coffee {}
Mivel szeretnénk megtartani a jelenlegi üzleti modellt, szeretnénk, ha a orderCoffee(CoffeeType type)
módszer a lehető legkevesebb változáson menne keresztül. Vessen egy pillantást rá:
public Coffee orderCoffee(CoffeeType type) {
Coffee coffee = coffeeFactory.createCoffee(type);
coffee.grindCoffee();
coffee.makeCoffee();
coffee.pourIntoCup();
System.out.println("Here's your coffee! Thanks! Come again!");
return coffee;
}
Milyen lehetőségeink vannak? Nos, már tudjuk, hogyan kell gyárat írni, igaz? A legegyszerűbb, ami rögtön eszünkbe jut, hogy írjunk két hasonló gyárat, majd adjuk át kávézónk kivitelezőjének a kívánt megvalósítást. Ezzel a kávézó osztálya nem változik. Először is létre kell hoznunk egy új gyári osztályt, örökölni kell az egyszerű gyárunkat, majd felül kell írni a createCoffee(CoffeeType type)
metódust. Írjunk gyárakat az olasz stílusú kávé és az amerikai stílusú kávé előállításához:
public class SimpleItalianCoffeeFactory extends SimpleCoffeeFactory {
@Override
public Coffee createCoffee(CoffeeType type) {
Coffee coffee = null;
switch (type) {
case AMERICANO:
coffee = new ItalianStyleAmericano();
break;
case ESPRESSO:
coffee = new ItalianStyleEspresso();
break;
case CAPPUCCINO:
coffee = new ItalianStyleCappuccino();
break;
case CAFFE_LATTE:
coffee = new ItalianStyleCaffeLatte();
break;
}
return coffee;
}
}
public class SimpleAmericanCoffeeFactory extends SimpleCoffeeFactory{
@Override
public Coffee createCoffee (CoffeeType type) {
Coffee coffee = null;
switch (type) {
case AMERICANO:
coffee = new AmericanStyleAmericano();
break;
case ESPRESSO:
coffee = new AmericanStyleEspresso();
break;
case CAPPUCCINO:
coffee = new AmericanStyleCappuccino();
break;
case CAFFE_LATTE:
coffee = new AmericanStyleCaffeLatte();
break;
}
return coffee;
}
}
Most átadhatjuk a kívánt gyári megvalósítást a CoffeeShopnak. Nézzük meg, hogyan nézne ki a különböző kávézókból történő kávérendelés kódja. Például olasz és amerikai stílusú cappuccino:
public class Main {
public static void main(String[] args) {
/*
Order an Italian-style cappuccino:
1. Create a factory for making Italian coffee
2. Create a new coffee shop, passing the Italian coffee factory to it through the constructor
3. Order our coffee
*/
SimpleItalianCoffeeFactory italianCoffeeFactory = new SimpleItalianCoffeeFactory();
CoffeeShop italianCoffeeShop = new CoffeeShop(italianCoffeeFactory);
italianCoffeeShop.orderCoffee(CoffeeType.CAPPUCCINO);
/*
Order an American-style cappuccino
1. Create a factory for making American coffee
2. Create a new coffee shop, passing the American coffee factory to it through the constructor
3. Order our coffee
*/
SimpleAmericanCoffeeFactory americanCoffeeFactory = new SimpleAmericanCoffeeFactory();
CoffeeShop americanCoffeeShop = new CoffeeShop(americanCoffeeFactory);
americanCoffeeShop.orderCoffee(CoffeeType.CAPPUCCINO);
}
}
Két különböző kávézót hoztunk létre, mindegyiknek átadva a kívánt gyárat. Egyrészt teljesítettük a célunkat, másrészt... Valahogy ez nem áll jól a vállalkozóknak... Találjuk ki, mi a baj. Először is a gyárak bősége. Mit? Most minden új helyszínhez saját gyárat kell létrehoznunk, és ezen felül ügyelnünk arra, hogy a kávézó létrehozásakor az érintett gyárat átadják a kivitelezőnek? Másodszor, ez még mindig egy egyszerű gyár. Csak kicsit modernizálva. De azért vagyunk itt, hogy megtanuljunk egy új mintát. Harmadszor, nem lehetséges más megközelítés? Jó lenne, ha a kávékészítéssel kapcsolatos összes kérdést bele tudnánk helyezniCoffeeShop
osztályba a kávékészítési folyamatok és a rendelések kiszolgálásának összekapcsolásával, ugyanakkor megfelelő rugalmasság fenntartása a különböző stílusú kávék elkészítéséhez. A válasz igen, megtehetjük. Ezt gyári módszer tervezési mintának nevezik.
Az egyszerű gyáritól a gyári módszerig
A feladat lehető leghatékonyabb megoldása érdekében:- Visszaadjuk a
createCoffee(CoffeeType type)
metódust azCoffeeShop
osztálynak. - Ezt a módszert absztrakttá tesszük.
- Maga az
CoffeeShop
osztály absztrakt lesz. - Az
CoffeeShop
osztálynak gyerekórái lesznek.
CoffeeShop
osztálynak a leszármazottja, amely createCoffee(CoffeeType type)
az olasz baristák legjobb hagyományainak megfelelően valósítja meg a módszert. Most lépésről lépésre. 1. lépés: Tegye Coffee
absztrakttá az osztályt. Két különböző termékcsaládunk van. Ennek ellenére az olasz és az amerikai kávéknak van egy közös őse – az Coffee
osztály. Helyénvaló lenne elvonatkoztatni:
public abstract class Coffee {
public void makeCoffee(){
// Brew the coffee
}
public void pourIntoCup(){
// Pour into a cup
}
}
2. lépés: Készítsen CoffeeShop
absztraktot, absztrakt createCoffee(CoffeeType type)
módszerrel
public abstract class CoffeeShop {
public Coffee orderCoffee(CoffeeType type) {
Coffee coffee = createCoffee(type);
coffee.makeCoffee();
coffee.pourIntoCup();
System.out.println("Here's your coffee! Thanks! Come again!");
return coffee;
}
protected abstract Coffee createCoffee(CoffeeType type);
}
3. lépés: Hozzon létre egy olasz kávézót, amely az absztrakt kávézó leszármazottja. createCoffee(CoffeeType type)
Az olasz receptek sajátosságait figyelembe véve valósítjuk meg benne a módszert.
public class ItalianCoffeeShop extends CoffeeShop {
@Override
public Coffee createCoffee (CoffeeType type) {
Coffee coffee = null;
switch (type) {
case AMERICANO:
coffee = new ItalianStyleAmericano();
break;
case ESPRESSO:
coffee = new ItalianStyleEspresso();
break;
case CAPPUCCINO:
coffee = new ItalianStyleCappuccino();
break;
case CAFFE_LATTE:
coffee = new ItalianStyleCaffeLatte();
break;
}
return coffee;
}
}
4. lépés Ugyanezt tesszük az amerikai stílusú kávézóval is
public class AmericanCoffeeShop extends CoffeeShop {
@Override
public Coffee createCoffee(CoffeeType type) {
Coffee coffee = null;
switch (type) {
case AMERICANO:
coffee = new AmericanStyleAmericano();
break;
case ESPRESSO:
coffee = new AmericanStyleEspresso();
break;
case CAPPUCCINO:
coffee = new AmericanStyleCappuccino();
break;
case CAFFE_LATTE:
coffee = new AmericanStyleCaffeLatte();
break;
}
return coffee;
}
}
5. lépés: Nézze meg, hogyan néz ki az amerikai és olasz tejeskávé:
public class Main {
public static void main(String[] args) {
CoffeeShop italianCoffeeShop = new ItalianCoffeeShop();
italianCoffeeShop.orderCoffee(CoffeeType.CAFFE_LATTE);
CoffeeShop americanCoffeeShop = new AmericanCoffeeShop();
americanCoffeeShop.orderCoffee(CoffeeType.CAFFE_LATTE);
}
}
Gratulálunk. Az imént a gyári módszer szerinti tervezési mintát valósítottuk meg kávézónk példájával.
A gyári módszerek mögött rejlő elv
Most nézzük meg részletesebben, mit kaptunk. Az alábbi diagram az eredményül kapott osztályokat mutatja. A zöld blokkok alkotói osztályok, a kék blokkok pedig termékosztályok.
- Minden termék az absztrakt osztály megvalósítása
Coffee
. - Minden alkotó az absztrakt osztály implementációja
CoffeeShop
. - Két párhuzamos osztályhierarchiát látunk:
- A termékek hierarchiája. Látunk olasz és amerikai leszármazottakat
- Az alkotók hierarchiája. Látunk olasz és amerikai leszármazottakat
- A
CoffeeShop
szuperosztálynak nincs információja arról, hogy melyik termék (Coffee
) jön létre. - A
CoffeeShop
szuperosztály egy adott termék létrehozását a leszármazottaira ruházza. - Az osztály minden leszármazottja
CoffeeShop
egycreateCoffee()
gyári metódust valósít meg a saját jellemzőinek megfelelően. Vagyis a termelői osztályok implementációi a termelői osztály sajátosságai alapján konkrét termékeket készítenek.
Gyári módszer felépítése

- A Creator osztály minden olyan metódust megvalósít, amely interakcióba lép a termékekkel, kivéve a gyári módszert.
- Az absztrakt
factoryMethod()
metódust az osztály összes leszármazottjának implementálnia kellCreator
. - Az
ConcreteCreator
osztály megvalósítja afactoryMethod()
metódust, amely közvetlenül létrehozza a terméket. - Ez az osztály felelős bizonyos termékek létrehozásáért. Ez az egyetlen osztály, amely információkat tartalmaz ezen termékek létrehozásáról.
- Minden terméknek közös interfészt kell megvalósítania, azaz egy közös termékosztály leszármazottjának kell lennie. Erre azért van szükség, hogy a termékeket használó osztályok absztrakcióként, nem pedig konkrét megvalósításként működhessenek rajtuk.
GO TO FULL VERSION