På dette tidspunkt har du sikkert allerede stødt på designmønstre. For eksempel singleton .

Lad os huske, hvad mønstre er, hvorfor de er nødvendige, og hvad kreative mønstre er (singleton er et eksempel). Vi vil også studere et nyt mønster: fabriksmetoden.

I softwareudvikling er et designmønster en gentagelig arkitektonisk konstruktion, der repræsenterer en løsning på et designproblem inden for en tilbagevendende kontekst.

Typisk er et mønster ikke en endelig løsning, der direkte kan konverteres til kode. Det er blot en modelløsning på et problem, som kan bruges i forskellige situationer.

Kreationsmønstre er designmønstre, der omhandler processen med at skabe objekter. De gør det muligt at skabe et system, der er uafhængigt af den metode, der bruges til at skabe, komponere og præsentere objekter.

En fabriksmetode er et kreativt designmønster, der definerer en fælles grænseflade til at skabe objekter i en overordnet klasse, hvilket giver dens efterkommere mulighed for at skabe disse objekter. På oprettelsestidspunktet kan efterkommere bestemme, hvilken klasse der skal oprettes.

Hvilket problem løser mønsteret?

Forestil dig, at du beslutter dig for at oprette et leveringsprogram. I første omgang vil du leje kurerer med biler og bruge enBilobjekt for at repræsentere et leveringskøretøj i programmet. Kurerer leverer pakker fra punkt A til punkt B og så videre. Nem peasy.

Programmet vinder popularitet. Din virksomhed vokser, og du ønsker at ekspandere til nye markeder. For eksempel kan du også begynde at levere mad og fragt. I dette tilfælde kan mad leveres af kurerer til fods, på scootere og på cykler, men lastbiler er nødvendige til fragt.

Nu skal du holde styr på flere ting (hvornår, til hvem, hvad og hvor meget der skal leveres), inklusive hvor meget hver kurer kan bære. De nye transportformer har forskellige hastigheder og kapaciteter. Så bemærker du, at de fleste enheder i dit program er stærkt knyttet tilBilklasse. Du indser, at for at få dit program til at fungere sammen med andre leveringsmetoder, bliver du nødt til at omskrive den eksisterende kodebase og gøre det igen, hver gang du tilføjer et nyt køretøj.

Resultatet er forfærdelig kode fyldt med betingede udsagn, der udfører forskellige handlinger afhængigt af typen af ​​transport.

Løsningen

Fabriksmetodemønsteret foreslår at skabe objekter ved at kalde en speciel fabriksmetode i stedet for direkte at bruge den nye operator. Underklasser af klassen, der har fabriksmetoden, kan ændre de oprettede objekter af de specifikke køretøjer. Ved første øjekast kan dette virke meningsløst: vi har simpelthen flyttet konstruktørkaldet fra et sted i programmet til et andet. Men nu kan du tilsidesætte fabriksmetoden i en underklasse for at ændre den type transport, der oprettes.

Lad os se på klassediagrammet for denne tilgang:

For at dette system kan fungere, skal alle de returnerede objekter have en fælles grænseflade. Underklasser vil være i stand til at producere objekter af forskellige klasser, der implementerer denne grænseflade.

For eksempel implementerer lastbil- og bilklasserne CourierTransport- grænsefladen med en leveringsmetode . Hver af disse klasser implementerer metoden på en anden måde: lastbiler leverer fragt, mens biler leverer mad, pakker og så videre. Fabriksmetoden i TruckCreator- klassen returnerer et lastbilobjekt, og CarCreator- klassen returnerer et bilobjekt.

For klienten af ​​fabriksmetoden er der ingen forskel mellem disse objekter, da den vil behandle dem som en slags abstrakt CourierTransport . Klienten vil bekymre sig meget om, at objektet har en metode til at levere, men hvordan præcis den metode fungerer, er ikke vigtigt.

Implementering i Java:


public interface CourierTransport {
	void deliver();
}
public class Car implements CourierTransport {
	@Override
	public void deliver() {
    		System.out.println("The package is being delivered by car");
	}
}
public class Truck implements CourierTransport {
	@Override
	public void deliver() {
    		System.out.println("The freight is being delivered by truck");
	}
}
public abstract class CourierTransportCreator {
	public abstract CourierTransport createTransport();
}
public class CarCreator extends CourierTransportCreator {
	@Override
	public CourierTransport createTransport() {
    		return new Car();
	}
}
public class TruckCreator extends CourierTransportCreator {
	@Override
	public CourierTransport createTransport() {
    		return new Truck();
	}
}
 
public class Delivery {
	private String address;
	private CourierTransport courierTransport;
 
	public void Delivery() {
	}
 
	public Delivery(String address, CourierTransport courierTransport) {
    	this.address = address;
    	this.courierTransport = courierTransport;
	}
 
	public CourierTransport getCourierTransport() {
    		return courierTransport;
	}
 
	public void setCourierTransport(CourierTransport courierTransport) {
    		this.courierTransport = courierTransport;
	}
 
	public String getAddress() {
    		return address;
	}
 
	public void setAddress(String address) {
    		this.address = address;
	}
}
public static void main(String[] args) {
    	// Accept a new type of order from the database (pseudocode)
    	String type = database.getTypeOfDeliver();
 
    	Delivery delivery = new Delivery();
    	
    	// Set the transport for delivery
        delivery.setCourierTransport(getCourierTransportByType(type));
    	
    	// Make the delivery
        delivery.getCourierTransport().deliver();
 
	}
 
	public static CourierTransport getCourierTransportByType(String type) {
    	switch (type) {
        	case "CarDelivery":
            	return new CarCreator().createTransport();
        	case "TruckDelivery":
            	return new TruckCreator().createTransport();
        	default:
            	throw new RuntimeException();
	    }
	}
    

Hvis vi ønsker at oprette et nyt leveringsobjekt, så opretter programmet automatisk et passende transportobjekt.

Hvornår skal vi anvende dette mønster?

1. Når du ikke på forhånd kender typer og afhængigheder af de objekter, som din kode skal arbejde med.

Fabriksmetoden adskiller koden til fremstilling af transportformer fra den kode, der bruger transporten. Som et resultat kan koden til oprettelse af objekter udvides uden at berøre resten af ​​koden.

For at tilføje understøttelse af en ny type transport for eksempel, skal du oprette en ny underklasse og definere en fabriksmetode i den, der returnerer en forekomst af den nye transport.

2. Når du vil spare systemressourcer ved at genbruge eksisterende objekter i stedet for at oprette nye.

Dette problem opstår normalt, når du arbejder med ressourcekrævende objekter, såsom databaseforbindelser, filsystemer osv.

Tænk på de trin, du skal tage for at genbruge eksisterende objekter:

  1. Først skal du oprette et delt lager for at gemme alle de objekter, du opretter.

  2. Når du anmoder om et nyt objekt, skal du kigge i depotet og kontrollere, om det indeholder et tilgængeligt objekt.

  3. Returner objektet til klientkoden.

  4. Men hvis der ikke er nogen tilgængelige objekter, skal du oprette et nyt og tilføje det til lageret.

Al denne kode skal placeres et sted, der ikke roder klientkoden. Det mest bekvemme sted ville være konstruktøren, da vi kun har brug for alle disse kontroller, når vi opretter objekter. Desværre opretter en konstruktør altid et nyt objekt - den kan ikke returnere et eksisterende objekt.

Det betyder, at der er brug for en anden metode, der kan returnere både eksisterende og nye objekter. Dette vil være fabriksmetoden.

3. Når du vil tillade brugere at udvide dele af dit framework eller bibliotek.

Brugere kan udvide dine rammeklasser gennem arv. Men hvordan får man rammerne til at skabe objekter af disse nye klasser i stedet for standardklasserne?

Løsningen er at lade brugerne udvide ikke kun komponenterne, men også de klasser, der skaber disse komponenter. Og til dette skal de skabende klasser have specifikke oprettelsesmetoder, der kan defineres.

Fordele

  • Afkobler en klasse fra specifikke transportklasser.
  • Holder koden til oprettelse af transportformer på ét sted, hvilket gør koden nemmere at vedligeholde.
  • Forenkler tilføjelsen af ​​nye transportformer til programmet.
  • Implementerer åben-lukket princippet.

Ulemper

Kan føre til store parallelle klassehierarkier, da hver produktklasse skal have sin egen skaberunderklasse.

Lad os opsummere

Du lærte om fabriksmetodemønsteret og så en mulig implementering. Dette mønster bruges ofte i forskellige biblioteker, der leverer objekter til at skabe andre objekter.

Brug fabriksmetodemønsteret, når du nemt vil tilføje nye objekter af underklasser af eksisterende klasser for at interagere med din primære forretningslogik og ikke blæse din kode op på grund af forskellige kontekster.