CodeGym/Java blog/Tilfældig/Designmønstre: Fabriksmetode
John Squirrels
Niveau
San Francisco

Designmønstre: Fabriksmetode

Udgivet i gruppen
Hej! I dag vil vi fortsætte med at studere designmønstre, og vi vil diskutere fabriksmetodemønsteret. Designmønstre: Fabriksmetode - 1 Du finder ud af, hvad det er, og hvilke opgaver dette mønster passer til. Vi vil overveje dette designmønster i praksis og studere dets struktur. For at sikre, at alt er klart, skal du forstå følgende emner:
  1. Arv i Java.
  2. Abstrakte metoder og klasser i Java

Hvilket problem løser fabriksmetoden?

Alle fabriksdesignmønstre har to typer deltagere: skabere (fabrikkerne selv) og produkter (objekterne skabt af fabrikkerne). Forestil dig følgende situation: Vi har en fabrik, der producerer biler med CodeGym-mærket. Den ved, hvordan man laver modeller af biler med forskellige typer karrosserier:
  • sedaner
  • stationcars
  • coupéer
Vores forretning trivedes så meget, at vi en skønne dag købte en anden bilproducent - OneAuto. Som fornuftige virksomhedsejere ønsker vi ikke at miste nogen OneAuto-kunder, og derfor står vi over for opgaven med at omstrukturere produktionen, så vi kan producere:
  • CodeGym sedaner
  • CodeGym stationcars
  • CodeGym coupéer
  • OneAuto sedans
  • OneAuto stationcars
  • OneAuto coupéer
Som du kan se, har vi nu to i stedet for én gruppe produkter, og de adskiller sig i visse detaljer. Fabriksmetodens designmønster er til, når vi skal skabe forskellige grupper af produkter, som hver især har nogle specifikke træk . Vi vil overveje dette mønsters vejledende princip i praksis, og gradvist bevæge os fra det enkle til det komplekse, ved at bruge eksemplet fra vores kaffebar, som vi skabte i en af ​​de foregående lektioner .

Lidt om fabriksmønsteret

Lad mig minde dig om, at vi tidligere byggede en lille virtuel kaffebar. Ved hjælp af en simpel fabrik lærte vi at lave forskellige typer kaffe. I dag vil vi omarbejde dette eksempel. Lad os huske, hvordan vores kaffebar så ud med dens enkle fabrik. Vi havde en kaffetime:
public class Coffee {
    public void grindCoffee(){
        // Grind the coffee
    }
    public void makeCoffee(){
        // Brew the coffee
    }
    public void pourIntoCup(){
        // Pour into a cup
    }
}
Og flere børneklasser svarende til bestemte typer kaffe, som vores fabrik kunne producere:
public class Americano extends Coffee {}
public class Cappuccino extends Coffee {}
public class CaffeLatte extends Coffee {}
public class Espresso extends Coffee {}
Vi har lavet en opregning for at gøre det nemt at afgive ordrer:
public enum CoffeeType {
    ESPRESSO,
    AMERICANO,
    CAFFE_LATTE,
    CAPPUCCINO
}
Selve kaffefabrikken så således ud:
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;
    }
}
Og endelig så selve kaffebaren sådan ud:
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;
    }
}

Modernisering af en simpel fabrik

Vores kaffebar kører rigtig godt. Så meget, at vi overvejer at udvide. Vi vil gerne åbne nogle nye lokationer. Vi er dristige og initiativrige, så vi vil ikke lave kedelige kaffebarer. Vi ønsker, at hver butik skal have et særligt twist. Derfor åbner vi til at begynde med to lokationer: en italiensk og en amerikansk. Disse ændringer vil påvirke ikke kun indretningen, men også de tilbudte drikkevarer:
  • i den italienske kaffebar vil vi udelukkende bruge italienske kaffemærker, med særlig maling og ristning.
  • det amerikanske sted vil have større portioner, og vi serverer skumfiduser med hver ordre.
Det eneste, der forbliver uændret, er vores forretningsmodel, som har vist sig at være fremragende. Med hensyn til koden er det, hvad der sker. Vi havde 4 klasser svarende til vores produkter:
public class Americano extends Coffee {}
public class Cappuccino extends Coffee {}
public class CaffeLatte extends Coffee {}
public class Espresso extends Coffee {}
Men nu har vi 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 {}
Da vi ønsker at beholde den nuværende forretningsmodel, ønsker vi, at orderCoffee(CoffeeType type)metoden undergår så få ændringer som muligt. Tag et kig på det:
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;
}
Hvilke muligheder har vi? Nå, vi ved allerede, hvordan man skriver en fabrik, ikke? Den enkleste ting, der umiddelbart kommer til at tænke på, er at skrive to lignende fabrikker, og derefter videregive den ønskede implementering til vores kaffebars konstruktør. Ved at gøre dette ændres kaffebarens klasse ikke. Først skal vi oprette en ny fabriksklasse, få den til at arve vores simple fabrik og derefter tilsidesætte metoden createCoffee(CoffeeType type). Lad os skrive fabrikker til at skabe kaffe i italiensk stil og kaffe i amerikansk stil:
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;
    }

}
Nu kan vi videregive den ønskede fabriksimplementering til CoffeeShop. Lad os se, hvordan koden til at bestille kaffe fra forskellige kaffebarer vil se ud. For eksempel cappuccino i italiensk stil og amerikansk stil:
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);
    }
}
Vi skabte to forskellige kaffebarer, og videregav den ønskede fabrik til hver. På den ene side har vi nået vores mål, men på den anden side... På en eller anden måde falder det her ikke godt ind hos iværksætterne... Lad os finde ud af, hvad der er galt. For det første overfloden af ​​fabrikker. Hvad? Nu er det meningen, at vi for hver ny lokation skal skabe sin egen fabrik og derudover sørge for, at den relevante fabrik videregives til konstruktøren, når vi opretter en kaffebar? For det andet er det stadig en simpel fabrik. Bare moderniseret lidt. Men vi er her for at lære et nyt mønster. For det tredje, er en anden tilgang ikke mulig? Det ville være fantastisk, hvis vi kunne sætte alle spørgsmål i forbindelse med kaffetilberedning ind iCoffeeShopklasse ved at forbinde processerne med at oprette kaffe og servicere ordrer, samtidig med at der opretholdes tilstrækkelig fleksibilitet til at lave forskellige kaffestile. Svaret er ja, det kan vi. Dette kaldes fabriksmetodens designmønster.

Fra en simpel fabrik til en fabriksmetode

For at løse opgaven så effektivt som muligt:
  1. Vi returnerer createCoffee(CoffeeType type)metoden til CoffeeShopklassen.
  2. Vi vil gøre denne metode abstrakt.
  3. Selve klassen CoffeeShopbliver abstrakt.
  4. Klassen CoffeeShopvil have børneklasser.
Ja ven. Den italienske kaffebar er intet andet end en efterkommer af klassen CoffeeShop, som implementerer createCoffee(CoffeeType type)metoden i overensstemmelse med de bedste traditioner fra italienske baristaer. Nu et skridt ad gangen. Trin 1. Gør Coffeeklassen abstrakt. Vi har to hele familier af forskellige produkter. Alligevel har den italienske og amerikanske kaffe en fælles forfader - klassen Coffee. Det ville være passende at gøre det abstrakt:
public abstract class Coffee {
    public void makeCoffee(){
        // Brew the coffee
    }
    public void pourIntoCup(){
        // Pour into a cup
    }
}
Trin 2. Lav CoffeeShopabstrakt med en abstrakt createCoffee(CoffeeType type)metode
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);
}
Trin 3. Opret en italiensk kaffebar, som er en efterkommer af den abstrakte kaffebar. Vi implementerer createCoffee(CoffeeType type)metoden i den under hensyntagen til detaljerne i italienske opskrifter.
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;
    }
}
Trin 4. Vi gør det samme for kaffebaren i amerikansk stil
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;
    }
}
Trin 5. Tjek hvordan amerikanske og italienske lattes vil se ud:
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);
    }
}
Tillykke. Vi har netop implementeret fabriksmetodens designmønster ved at bruge vores kaffebar som eksempel.

Princippet bag fabriksmetoder

Lad os nu overveje mere detaljeret, hvad vi fik. Diagrammet nedenfor viser de resulterende klasser. De grønne blokke er skaberklasser, og de blå blokke er produktklasser. Designmønstre: Fabriksmetode - 2Hvilke konklusioner kan vi drage?
  1. Alle produkter er implementeringer af den abstrakte Coffeeklasse.
  2. Alle skabere er implementeringer af den abstrakte CoffeeShopklasse.
  3. Vi ser to parallelle klassehierarkier:
    • Hierarki af produkter. Vi ser italienske efterkommere og amerikanske efterkommere
    • Hierarki af skabere. Vi ser italienske efterkommere og amerikanske efterkommere
  4. Superklassen CoffeeShophar ingen information om, hvilket specifikt produkt ( Coffee) der vil blive oprettet.
  5. Superklassen CoffeeShopuddelegerer skabelsen af ​​et specifikt produkt til sine efterkommere.
  6. Hver efterkommer af CoffeeShopklassen implementerer en createCoffee()fabriksmetode i overensstemmelse med sine egne specifikke funktioner. Med andre ord forbereder implementeringerne af producentklasserne specifikke produkter baseret på producentklassens specifikationer.
Du er nu klar til definitionen af ​​fabriksmetodemønsteret . Fabriksmetodemønsteret definerer en grænseflade til oprettelse af et objekt, men tillader underklasser at vælge klassen for det oprettede objekt. Således uddelegerer en fabriksmetode oprettelse af en instans til underklasser. Generelt er det ikke så vigtigt at huske definitionen som at forstå, hvordan det hele fungerer.

Struktur af en fabriksmetode

Designmønstre: Fabriksmetode - 3Diagrammet ovenfor viser den generelle struktur af fabriksmetodemønsteret. Hvad er ellers vigtigt her?
  1. Creator-klassen implementerer alle metoder, der interagerer med produkter, undtagen fabriksmetoden.
  2. Den abstrakte factoryMethod()metode skal implementeres af alle efterkommere af Creatorklassen.
  3. Klassen ConcreteCreatorimplementerer factoryMethod()metoden, som direkte skaber produktet.
  4. Denne klasse er ansvarlig for at skabe specifikke produkter. Dette er den eneste klasse med information om oprettelse af disse produkter.
  5. Alle produkter skal implementere en fælles grænseflade, dvs. de skal være efterkommere af en fælles produktklasse. Dette er nødvendigt, så klasser, der bruger produkter, kan fungere på dem som abstraktioner, snarere end specifikke implementeringer.

Lektier

I dag har vi gjort en del arbejde og studeret fabriksmetodens designmønster. Det er tid til at forstærke materialet! Øvelse 1. Gør arbejdet med at åbne endnu en kaffebar. Det kunne være en kaffebar i engelsk stil eller spansk stil. Eller endda rumskibsstil. Tilføj madfarve til kaffen for at få den til at gløde, og din kaffe vil simpelthen være ude af denne verden! Øvelse 2. I sidste lektion havde du en øvelse, hvor du lavede en virtuel sushibar eller et virtuelt pizzeria. Nu er din øvelse at ikke stå stille. I dag lærte du at bruge fabriksmetoden til din fordel. Det er tid til at bruge denne viden og udvide din egen forretning ;)
Kommentarer
  • Populær
  • Ny
  • Gammel
Du skal være logget ind for at skrive en kommentar
Denne side har ingen kommentarer endnu