Bună! Astăzi vom continua să studiem modelele de design și vom discuta despre modelul metodei din fabrică.
Veți afla ce este și pentru ce sarcini este potrivit acest model. Vom lua în considerare acest model de design în practică și vom studia structura lui. Pentru a vă asigura că totul este clar, trebuie să înțelegeți următoarele subiecte:
Ce concluzii putem face?
Diagrama de mai sus arată structura generală a modelului metodei din fabrică. Ce altceva este important aici?

- Moștenirea în Java.
- Metode și clase abstracte în Java
Ce problemă rezolvă metoda din fabrică?
Toate modelele de design din fabrică au două tipuri de participanți: creatori (fabricile în sine) și produsele (obiectele create de fabrici). Imaginează-ți următoarea situație: avem o fabrică care produce mașini cu marca CodeGym. Știe cum să creeze modele de mașini cu diferite tipuri de caroserie:- berline
- vagoane break
- coupe-uri
- Sedan CodeGym
- CodeGym break
- Coupe-uri CodeGym
- Sedanuri OneAuto
- OneAuto break
- Coupe-uri OneAuto
Un pic despre modelul din fabrică
Permiteți-mi să vă reamintesc că anterior am construit o mică cafenea virtuală. Cu ajutorul unei simple fabrici, am învățat cum să creăm diferite tipuri de cafea. Astăzi vom relua acest exemplu. Să ne amintim cum arăta cafeneaua noastră, cu fabrica sa simplă. Am avut un curs de cafea:
public class Coffee {
public void grindCoffee(){
// Grind the coffee
}
public void makeCoffee(){
// Brew the coffee
}
public void pourIntoCup(){
// Pour into a cup
}
}
Și câteva clase de copii corespunzătoare unor tipuri specifice de cafea pe care fabrica noastră le-ar putea produce:
public class Americano extends Coffee {}
public class Cappuccino extends Coffee {}
public class CaffeLatte extends Coffee {}
public class Espresso extends Coffee {}
Am creat o enumerare pentru a facilita plasarea comenzilor:
public enum CoffeeType {
ESPRESSO,
AMERICANO,
CAFFE_LATTE,
CAPPUCCINO
}
Fabrica de cafea în sine arăta astfel:
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;
}
}
Și, în sfârșit, cafeneaua în sine arăta astfel:
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;
}
}
Modernizarea unei fabrici simple
Cafeneaua noastră funcționează foarte bine. Atât de mult încât ne gândim să ne extindem. Vrem să deschidem câteva locații noi. Suntem îndrăzneți și întreprinzători, așa că nu vom scoate cafenele plictisitoare. Ne dorim ca fiecare magazin să aibă o întorsătură specială. În consecință, pentru început, vom deschide două locații: una italiană și una americană. Aceste modificări vor afecta nu numai designul interior, ci și băuturile oferite:- în cafeneaua italiană vom folosi exclusiv mărci italiene de cafea, cu măcinare și prăjire specială.
- locația americană va avea porții mai mari și vom servi marshmallows la fiecare comandă.
public class Americano extends Coffee {}
public class Cappuccino extends Coffee {}
public class CaffeLatte extends Coffee {}
public class Espresso extends Coffee {}
Dar acum vom avea 8:
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 {}
Din moment ce vrem să păstrăm modelul de afaceri actual, dorim ca orderCoffee(CoffeeType type)
metoda să sufere cât mai puține modificări. Aruncă o privire la el:
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;
}
Ce optiuni avem? Ei bine, știm deja să scriem o fabrică, nu? Cel mai simplu lucru care ne vine imediat în minte este să scriem două fabrici similare, apoi să trecem implementarea dorită către constructorul cafenelei noastre. Făcând acest lucru, clasa cafenelei nu se va schimba. În primul rând, trebuie să creăm o nouă clasă de fabrică, să o facem să moștenească fabrica noastră simplă și apoi să înlocuim metoda createCoffee(CoffeeType type)
. Să scriem fabrici pentru a crea cafea în stil italian și cafea în stil american:
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;
}
}
Acum putem trece implementarea dorită din fabrică către CoffeeShop. Să vedem cum ar arăta codul pentru comandarea cafelei de la diferite cafenele. De exemplu, cappuccino în stil italian și american:
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);
}
}
Am creat două cafenele diferite, trecând fiecare fabrica dorită. Pe de o parte, ne-am îndeplinit obiectivul, dar pe de altă parte... Cumva, acest lucru nu le convine antreprenorilor... Să ne dăm seama ce este în neregulă. În primul rând, abundența fabricilor. Ce? Acum, pentru fiecare locație nouă, ar trebui să ne creăm propria fabrică și, în plus, să ne asigurăm că fabrica relevantă este transmisă constructorului atunci când creăm o cafenea? În al doilea rând, este încă o simplă fabrică. Doar modernizat ușor. Dar suntem aici pentru a învăța un nou model. În al treilea rând, nu este posibilă o abordare diferită? Ar fi grozav dacă am putea pune toate problemele legate de prepararea cafelei înCoffeeShop
clasă prin conectarea proceselor de creare a cafelei și a comenzilor de service, menținând în același timp o flexibilitate suficientă pentru a face diferite stiluri de cafea. Răspunsul este da, putem. Acesta se numește modelul de proiectare al metodei din fabrică.
De la o simplă fabrică la o metodă de fabrică
Pentru a rezolva sarcina cât mai eficient posibil:- Revenim
createCoffee(CoffeeType type)
metoda înCoffeeShop
clasă. - Vom face această metodă abstractă.
- Clasa
CoffeeShop
în sine va deveni abstractă. - Clasa
CoffeeShop
va avea cursuri pentru copii.
CoffeeShop
clasei, care implementează createCoffee(CoffeeType type)
metoda în conformitate cu cele mai bune tradiții ale baristilor italieni. Acum, câte un pas. Pasul 1. Faceți Coffee
clasa abstractă. Avem două familii întregi de produse diferite. Totuși, cafeaua italiană și americană au un strămoș comun - Coffee
clasa. Ar fi corect să o facem abstractă:
public abstract class Coffee {
public void makeCoffee(){
// Brew the coffee
}
public void pourIntoCup(){
// Pour into a cup
}
}
Pasul 2. Faceți CoffeeShop
abstract, cu o createCoffee(CoffeeType type)
metodă abstractă
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);
}
Pasul 3. Creați o cafenea italiană, care este un descendent al cafenelei abstracte. Implementăm createCoffee(CoffeeType type)
metoda în ea, ținând cont de specificul rețetelor italiene.
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;
}
}
Pasul 4. Facem la fel și pentru cafeneaua în stil american
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;
}
}
Pasul 5. Vezi cum vor arăta latte-urile americane și italiene:
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);
}
}
Felicitări. Tocmai am implementat modelul de proiectare a metodei din fabrică folosind cafeneaua noastră ca exemplu.
Principiul din spatele metodelor din fabrică
Acum să luăm în considerare mai în detaliu ce avem. Diagrama de mai jos prezintă clasele rezultate. Blocurile verzi sunt clase de creatori, iar blocurile albastre sunt clase de produse.
- Toate produsele sunt implementări ale
Coffee
clasei abstracte. - Toți creatorii sunt implementări ale
CoffeeShop
clasei abstracte. - Vedem două ierarhii de clasă paralele:
- Ierarhia produselor. Vedem descendenți italieni și descendenți americani
- Ierarhia creatorilor. Vedem descendenți italieni și descendenți americani
- Superclasa
CoffeeShop
nu are informații despre ce anume produs (Coffee
) va fi creat. - Superclasa
CoffeeShop
deleagă urmașilor săi crearea unui produs specific. - Fiecare descendent al
CoffeeShop
clasei implementează ocreateCoffee()
metodă din fabrică în conformitate cu propriile caracteristici specifice. Cu alte cuvinte, implementările claselor de producători pregătesc produse specifice pe baza specificului clasei de producători.
Structura unei metode din fabrică

- Clasa Creator implementează toate metodele care interacționează cu produsele, cu excepția metodei din fabrică.
- Metoda abstractă
factoryMethod()
trebuie implementată de toți descendenții claseiCreator
. - Clasa
ConcreteCreator
implementeazăfactoryMethod()
metoda, care creează direct produsul. - Această clasă este responsabilă pentru crearea unor produse specifice. Aceasta este singura clasă cu informații despre crearea acestor produse.
- Toate produsele trebuie să implementeze o interfață comună, adică trebuie să fie descendenți ai unei clase de produse comune. Acest lucru este necesar pentru ca clasele care folosesc produse să poată opera asupra lor ca abstracții, mai degrabă decât implementări specifice.
GO TO FULL VERSION