Vid det här laget har du förmodligen redan stött på designmönster. Till exempel singleton .

Låt oss komma ihåg vad mönster är, varför de behövs och vad skapande mönster är (singleton är ett exempel). Vi ska också studera ett nytt mönster: fabriksmetoden.

Inom mjukvaruutveckling är ett designmönster en repeterbar arkitektonisk konstruktion som representerar en lösning på ett designproblem inom något återkommande sammanhang.

Vanligtvis är ett mönster inte en slutlig lösning som direkt kan konverteras till kod. Det är bara en modelllösning på ett problem som kan användas i olika situationer.

Skapande mönster är designmönster som handlar om processen att skapa objekt. De gör det möjligt att skapa ett system som är oberoende av den metod som används för att skapa, komponera och presentera objekt.

En fabriksmetod är ett kreativt designmönster som definierar ett gemensamt gränssnitt för att skapa objekt i en överordnad klass, vilket ger dess avkomlingar möjlighet att skapa dessa objekt. Vid skapandet kan efterkommande bestämma vilken klass som ska skapas.

Vilket problem löser mönstret?

Föreställ dig att du bestämmer dig för att skapa ett leveransprogram. Till en början kommer du att hyra kurirer med bilar och använda enBilobjekt för att representera ett leveransfordon i programmet. Bud levererar paket från punkt A till punkt B och så vidare. Lätt som en plätt.

Programmet ökar i popularitet. Ditt företag växer och du vill expandera till nya marknader. Du kan till exempel börja även leverera mat och fraktfrakt. I det här fallet kan mat levereras av bud till fots, på skotrar och på cyklar, men lastbilar behövs för frakt.

Nu behöver du hålla reda på flera saker (när, till vem, vad och hur mycket som kommer att levereras), inklusive hur mycket varje bud kan bära. De nya transportsätten har olika hastigheter och kapacitet. Då märker du att de flesta enheter i ditt program är starkt knutna tillBilklass. Du inser att för att få ditt program att fungera med andra leveransmetoder måste du skriva om den befintliga kodbasen och göra det igen varje gång du lägger till ett nytt fordon.

Resultatet är fruktansvärd kod fylld med villkorliga uttalanden som utför olika åtgärder beroende på typen av transport.

Lösningen

Fabriksmetodmönstret föreslår att man skapar objekt genom att anropa en speciell fabriksmetod istället för att direkt använda den nya operatorn. Underklasser av klassen som har fabriksmetoden kan modifiera de skapade objekten för de specifika fordonen. Vid första anblicken kan detta verka meningslöst: vi har helt enkelt flyttat konstruktoranropet från en plats i programmet till en annan. Men nu kan du åsidosätta fabriksmetoden i en underklass för att ändra typen av transport som skapas.

Låt oss titta på klassdiagrammet för detta tillvägagångssätt:

För att detta system ska fungera måste alla returnerade objekt ha ett gemensamt gränssnitt. Underklasser kommer att kunna producera objekt av olika klasser som implementerar detta gränssnitt.

Till exempel implementerar klasserna Truck och Car CourierTransport- gränssnittet med en leveransmetod . Var och en av dessa klasser implementerar metoden på olika sätt: lastbilar levererar frakt, medan bilar levererar mat, paket och så vidare. Fabriksmetoden i TruckCreator -klassen returnerar ett lastbilsobjekt och CarCreator -klassen returnerar ett bilobjekt.

För klienten av fabriksmetoden är det ingen skillnad mellan dessa objekt, eftersom det kommer att behandla dem som någon form av abstrakt CourierTransport . Kunden kommer att bry sig mycket om att objektet har en metod för att leverera, men hur exakt den metoden fungerar är inte viktigt.

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();
	    }
	}

Om vi ​​vill skapa ett nytt leveransobjekt skapar programmet automatiskt ett lämpligt transportobjekt.

När ska vi tillämpa detta mönster?

1. När du inte i förväg vet vilka typer och beroenden av objekten som din kod behöver arbeta med.

Fabriksmetoden skiljer koden för att producera transportformer från koden som använder transporten. Som ett resultat kan koden för att skapa objekt utökas utan att röra resten av koden.

Till exempel, för att lägga till stöd för en ny typ av transport, måste du skapa en ny underklass och definiera en fabriksmetod i den som returnerar en instans av den nya transporten.

2. När du vill spara systemresurser genom att återanvända befintliga objekt istället för att skapa nya.

Detta problem uppstår vanligtvis när man arbetar med resurskrävande objekt, som databasanslutningar, filsystem, etc.

Tänk på de steg du behöver ta för att återanvända befintliga objekt:

  1. Först måste du skapa ett delat arkiv för att lagra alla objekt du skapar.

  2. När du begär ett nytt objekt måste du titta i förvaret och kontrollera om det innehåller ett tillgängligt objekt.

  3. Returnera objektet till klientkoden.

  4. Men om det inte finns några tillgängliga objekt, skapa ett nytt och lägg till det i förvaret.

All den här koden måste placeras någonstans som inte belamrar klientkoden. Den mest bekväma platsen skulle vara konstruktören, eftersom vi bara behöver alla dessa kontroller när vi skapar objekt. Tyvärr skapar en konstruktör alltid ett nytt objekt — den kan inte returnera ett befintligt objekt.

Det betyder att det behövs en annan metod som kan returnera både befintliga och nya objekt. Detta kommer att vara fabriksmetoden.

3. När du vill tillåta användare att utöka delar av ditt ramverk eller bibliotek.

Användare kan utöka dina ramklasser genom arv. Men hur får man ramverket att skapa objekt av dessa nya klasser snarare än de vanliga?

Lösningen är att låta användare utöka inte bara komponenterna, utan även klasserna som skapar dessa komponenter. Och för detta måste de skapande klasserna ha specifika skapandemetoder som kan definieras.

Fördelar

  • Frikopplar en klass från specifika transportklasser.
  • Håller koden för att skapa transportformer på ett ställe, vilket gör koden lättare att underhålla.
  • Förenklar tillägget av nya transportsätt till programmet.
  • Implementerar öppet-stängt-principen.

Nackdelar

Kan leda till stora parallella klasshierarkier, eftersom varje produktklass måste ha sin egen skaparunderklass.

Låt oss sammanfatta

Du lärde dig om fabriksmetodens mönster och såg en möjlig implementering. Detta mönster används ofta i olika bibliotek som tillhandahåller objekt för att skapa andra objekt.

Använd fabriksmetoden när du enkelt vill lägga till nya objekt av underklasser av befintliga klasser för att interagera med din huvudsakliga affärslogik och inte svälla din kod på grund av olika sammanhang.