Hei venn! I dag skal vi fortsette å studere designmønstre. I denne leksjonen skal vi snakke om fabrikker. Vi skal diskutere problemet som dette mønsteret løser og se på et eksempel på hvordan en fabrikk kan hjelpe deg med å åpne en kaffebar. I tillegg vil jeg gi deg 5 enkle trinn for å lage en fabrikk. Fabrikkdesignmønster - 1 For å være sikker på at vi alle er på samme bølgelengde og at du raskt forstår dette konseptet, bør du være kjent med følgende emner:
  • Arv i Java
  • Innsnevring og utvidelse av referansetyper i Java
  • Interaksjon mellom ulike klasser og objekter.

Hva er en fabrikk?

Fabrikkdesignmønsteret lar deg kontrollere opprettelsen av objekter. Prosessen med å lage et nytt objekt er ikke superenkelt, men det er heller ikke altfor komplisert. Vi vet alle at vi trenger operatøren newfor å lage et nytt objekt. Kanskje ser det ut til at det ikke er noe å kontrollere her, men det stemmer ikke. Anta at vår applikasjon har en viss klasse som har mange etterkommere. Det kan oppstå vanskeligheter når det er nødvendig å opprette en forekomst av en bestemt klasse avhengig av visse forhold. En fabrikk er et designmønster som hjelper til med å løse problemet med å lage ulike objekter avhengig av visse forhold. Hvordan er det for et abstrakt konsept? Dette vil bli klarere og mer spesifikt når vi ser på eksemplet nedenfor.

La oss tilberede ulike typer kaffe

Anta at vi ønsker å automatisere en kaffebar. Vi må lære programmet vårt hvordan man lager forskjellige typer kaffe. For å gjøre dette vil vi lage en kaffeklasse og noen få derivatklasser for å representere kaffetypene vi skal tilberede: Americano, cappuccino, espresso og latte. La oss starte med en generell kaffetime:

public class Coffee {
    public void grindCoffee(){
        // Grind the coffee
    }
    public void makeCoffee(){
        // Brew the coffee
    }
    public void pourIntoCup(){
        // Pour into a cup
    }
}
Deretter oppretter vi barneklassene:

public class Americano extends Coffee {}
public class Cappuccino extends Coffee {}
public class CaffeLatte extends Coffee {}
public class Espresso extends Coffee {}
Våre kunder kan bestille alle typer kaffe. Bestillingene deres må sendes til programmet. Dette kan gjøres på mange måter, for eksempel ved å bruke String. Men an enumer best for dette. Vi oppretter enumog definerer enum-felter som tilsvarer kaffetypene som kan bestilles:

public enum CoffeeType {
    ESPRESSO,
    AMERICANO,
    CAFFE_LATTE,
    CAPPUCCINO
}
Flott. La oss nå skrive koden for kaffebaren vår:

public class CoffeeShop {
    
    public Coffee orderCoffee(CoffeeType type) {
        Coffee coffee = null;
        
        switch (type) {
            case AMERICANO:
                coffee = new Americano();
                break;
            case ESPRESSO:
                coffee = new Espresso();
                break;
            case CAPPUCCINO:
                coffee = new Cappucсino();
                break;
            case CAFFE_LATTE:
                coffee = new CaffeLatte();
                break;
        }

        coffee.grindCoffee();
        coffee.makeCoffee();
        coffee.pourIntoCup();

        System.out.println("Here's your coffee! Thanks! Come again!");
        return coffee;
    }
}
Metoden orderCoffeekan deles inn i to deler:
  1. Oppretting av en spesifikk forekomst av kaffe i en switchuttalelse. Det er her en fabrikk gjør det den gjør - lage en bestemt type avhengig av forholdene.
  2. Forberedelse - dette er maling, brygging og helling i en kopp.
Her er det som er viktig å vite hvis du trenger å gjøre endringer i metoden i fremtiden:
  1. Trinnene som er involvert i selve tilberedningen (maling, brygging og helling i en kopp) vil forbli uendret (i det minste regner vi med dette).
  2. Men utvalget av kaffe kan endre seg. Kanskje vi begynner å lage mokka... Frappu... Mochacci... Uansett, en ny type kaffe.
Vi kan allerede nå være ganske sikre på at vi i fremtiden må gjøre endringer i metodeuttalelsen switch. Det er også mulig at i vår kaffebar orderCoffeevil metoden ikke være det eneste stedet hvor vi lager forskjellige typer kaffe. Det vil derfor måtte gjøres endringer flere steder. Du forstår sikkert allerede hva jeg mener. Vi må refaktorere. Flytt blokken som er ansvarlig for å lage kaffe til en egen klasse av to grunner:
  1. Vi kan gjenbruke kaffekokingslogikken andre steder.
  2. Hvis sortimentet endres, trenger vi ikke å redigere koden overalt hvor kaffen lages. Det vil være nok å endre koden vår på bare ett sted.
Tiden er med andre ord inne for å sette opp en fabrikk.

Setter opp vår første fabrikk

For å gjøre dette oppretter vi en ny klasse som kun er ansvarlig for å lage de nødvendige forekomstene av kaffeklasser:

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 Cappucino();
                break;
            case CAFFE_LATTE:
                coffee = new CaffeLatte();
                break;
        }
        
        return coffee;
    }
}
Gratulerer! Vi har nettopp implementert fabrikkdesignmønsteret i sin enkleste form (nesten). Det kunne vært enda enklere om vi gjorde createCoffeemetoden statisk. Men da ville vi miste to evner:
  1. Evnen til å arve SimpleCoffeeFactoryog overstyre createCoffeemetoden.
  2. Muligheten til å legge til den nødvendige fabrikkimplementeringen til våre klasser.
Forresten, apropos implementering... Vi må tilbake til kaffebaren og legge til kaffefabrikken vår.

Legger til en fabrikk til kaffebaren

La oss omskrive kaffebarklassen ved å bruke en fabrikk:

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;
    }
}
Utmerket. Nå skal vi gi en kortfattet beskrivelse av den generelle strukturen til fabrikkdesignmønsteret.

5 trinn for å åpne din egen fabrikk

Trinn 1. Programmet ditt har en klasse med flere etterkommere, som i diagrammet nedenfor: Fabrikkdesignmønster - 2Trinn 2. Du oppretter et enummed et felt for hver barneklasse:

    enum CatType {
        LION,
        TIGER,
        FLUFFY
    }
Trinn 3. Bygg fabrikken din. Kall det CatFactory. Her er koden:

class CatFactory {}
Trinn 4. På fabrikken din, lag en createCatmetode som tar et CatTypeargument. Her er koden:

    class CatFactory {
        public Cat createCat(CatType type) {
            
        }
    }
Trinn 5. I hoveddelen av metoden skriver du en switchsetning som teller opp enum-feltene og oppretter en forekomst av klassen som tilsvarer den beståtte enumverdien:

class CatFactory {
        public Cat createCat(CatType type) {
            Cat cat = null;
            
            switch (type) {
                case LION:
                    cat =  new Fluffy();
                    break;
                case TIGER:
                    cat = new Tiger();
                    break;
                case FLUFFY:
                    cat =  new Lion();
                    break;
            }
            
            return cat;
        }
    }
Nå kan du drive en fabrikk som en sjef. :)

Hvordan øve

Å lese er bra, å skrive kode er enda bedre. Hvis navnet ditt har et partall bokstaver, kan du prøve å lage din egen virtuelle pizzeria. Hvis navnet ditt har et oddetall bokstaver, kan du prøve å lage en virtuell sushibar. Hvis du ikke har noe navn, var du heldig. I dag kan du slappe av.