CodeGym /Blog Java /Aleatoriu /Modele de proiectare: metoda fabricii
John Squirrels
Nivel
San Francisco

Modele de proiectare: metoda fabricii

Publicat în grup
Bună! Astăzi vom continua să studiem modelele de design și vom discuta despre modelul metodei din fabrică. Modele de proiectare: metoda fabricii - 1 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:
  1. Moștenirea în Java.
  2. 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
Afacerea noastră a prosperat atât de mult încât într-o bună zi am achiziționat un alt producător de automobile – OneAuto. Fiind proprietari de afaceri sensibili, nu dorim să pierdem niciun client OneAuto și, prin urmare, ne confruntăm cu sarcina de a restructura producția astfel încât să putem produce:
  • Sedan CodeGym
  • CodeGym break
  • Coupe-uri CodeGym
  • Sedanuri OneAuto
  • OneAuto break
  • Coupe-uri OneAuto
După cum puteți vedea, în loc de un grup de produse, acum avem două și diferă în anumite detalii. Modelul de proiectare a metodei din fabrică este pentru atunci când trebuie să creăm diferite grupuri de produse, fiecare dintre ele având anumite trăsături specifice. Vom lua în considerare principiul călăuzitor al acestui tipar în practică, trecând treptat de la simplu la complex, folosind exemplul cafenelei noastre, pe care am creat-o într-una din lecțiile anterioare .

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ă.
Singurul lucru care rămâne neschimbat este modelul nostru de afaceri, care s-a dovedit a fi excelent. În ceea ce privește codul, asta se întâmplă. Am avut 4 clase corespunzătoare produselor noastre:

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 înCoffeeShopclasă 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:
  1. Revenim createCoffee(CoffeeType type)metoda în CoffeeShopclasă.
  2. Vom face această metodă abstractă.
  3. Clasa CoffeeShopîn sine va deveni abstractă.
  4. Clasa CoffeeShopva avea cursuri pentru copii.
Da prietene. Cafeneaua italiană nu este altceva decât un descendent al CoffeeShopclasei, 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 Coffeeclasa abstractă. Avem două familii întregi de produse diferite. Totuși, cafeaua italiană și americană au un strămoș comun - Coffeeclasa. 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 CoffeeShopabstract, 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. Modele de proiectare: metoda fabricii - 2Ce concluzii putem face?
  1. Toate produsele sunt implementări ale Coffeeclasei abstracte.
  2. Toți creatorii sunt implementări ale CoffeeShopclasei abstracte.
  3. 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
  4. Superclasa CoffeeShopnu are informații despre ce anume produs ( Coffee) va fi creat.
  5. Superclasa CoffeeShopdeleagă urmașilor săi crearea unui produs specific.
  6. Fiecare descendent al CoffeeShopclasei implementează o createCoffee()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.
Acum sunteți gata pentru definirea modelului metodei din fabrică . Modelul metodei din fabrică definește o interfață pentru crearea unui obiect, dar permite subclaselor să selecteze clasa obiectului creat. Astfel, o metodă din fabrică deleagă crearea unei instanțe subclaselor. În general, amintirea definiției nu este la fel de importantă precum înțelegerea modului în care funcționează totul.

Structura unei metode din fabrică

Modele de proiectare: metoda fabricii - 3Diagrama de mai sus arată structura generală a modelului metodei din fabrică. Ce altceva este important aici?
  1. Clasa Creator implementează toate metodele care interacționează cu produsele, cu excepția metodei din fabrică.
  2. Metoda abstractă factoryMethod()trebuie implementată de toți descendenții clasei Creator.
  3. Clasa ConcreteCreatorimplementează factoryMethod()metoda, care creează direct produsul.
  4. Această clasă este responsabilă pentru crearea unor produse specifice. Aceasta este singura clasă cu informații despre crearea acestor produse.
  5. 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.

Teme pentru acasă

Astăzi am lucrat destul de mult și am studiat modelul de proiectare a metodei din fabrică. Este timpul să întăriți materialul! Exercițiul 1. Faceți treaba pentru a deschide o altă cafenea. Ar putea fi o cafenea în stil englezesc sau spaniol. Sau chiar în stilul unei nave spațiale. Adăugați colorant alimentar cafelei pentru a o face să strălucească, iar cafeaua dvs. va fi pur și simplu ieșită din lumea asta! Exercițiul 2. În ultima lecție , ai avut un exercițiu în care ai creat un sushi bar virtual sau o pizzerie virtuală. Acum exercițiul tău este să nu stai pe loc. Astăzi ai învățat cum să folosești modelul metodei din fabrică în avantajul tău. Este timpul să folosiți aceste cunoștințe și să vă extindeți propria afacere ;)
Comentarii
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION