În acest moment, probabil că ați întâlnit deja modele de design. De exemplu, singleton .

Să ne amintim ce modele sunt, de ce sunt necesare și care sunt modelele creaționale (singleton este un exemplu). Vom studia, de asemenea, un model nou: metoda fabricii.

În dezvoltarea de software, un model de design este o construcție arhitecturală repetabilă care reprezintă o soluție la o problemă de proiectare într-un context recurent.

De obicei, un model nu este o soluție finală care poate fi convertită direct în cod. Este doar o soluție model la o problemă care poate fi folosită în diverse situații.

Modelele de creație sunt modele de design care se ocupă de procesul de creare a obiectelor. Ele fac posibilă crearea unui sistem care este independent de metoda utilizată pentru a crea, compune și prezenta obiecte.

O metodă fabrică este un model de design creațional care definește o interfață comună pentru crearea de obiecte într-o clasă părinte, oferind descendenților săi posibilitatea de a crea aceste obiecte. La momentul creării, descendenții pot determina ce clasă să creeze.

Ce problemă rezolvă modelul?

Imaginați-vă că decideți să creați un program de livrare. Inițial, vei angaja curieri cu mașini și vei folosi aMașinăobiect pentru a reprezenta un vehicul de livrare în program. Curierii livrează pachete de la punctul A la punctul B și așa mai departe. Ușor de gălăgie.

Programul câștigă popularitate. Afacerea dvs. este în creștere și doriți să vă extindeți pe noi piețe. De exemplu, puteți începe să livrați alimente și să expediați mărfuri. În acest caz, alimentele pot fi livrate prin curieri pe jos, cu scutere și pe biciclete, dar pentru transportul de marfă sunt necesare camioane.

Acum trebuie să urmăriți mai multe lucruri (când, cui, ce și cât va fi livrat), inclusiv cât poate transporta fiecare curier. Noile moduri de transport au viteze și capacități diferite. Apoi observați că majoritatea entităților din programul dvs. sunt strâns legate deMașinăclasă. Vă dați seama că pentru ca programul dvs. să funcționeze cu alte metode de livrare, va trebui să rescrieți baza de cod existentă și să faceți asta din nou de fiecare dată când adăugați un vehicul nou.

Rezultatul este un cod groaznic plin cu instrucțiuni condiționate care efectuează diferite acțiuni în funcție de tipul de transport.

Soluția

Modelul metodei din fabrică sugerează crearea de obiecte prin apelarea unei metode speciale din fabrică, mai degrabă decât prin utilizarea directă a noului operator. Subclasele clasei care are metoda fabrică pot modifica obiectele create ale vehiculelor specifice. La prima vedere, acest lucru poate părea inutil: pur și simplu am mutat apelul constructorului dintr-un loc în program în altul. Dar acum puteți suprascrie metoda din fabrică într-o subclasă pentru a schimba tipul de transport creat.

Să ne uităm la diagrama de clasă pentru această abordare:

Pentru ca acest sistem să funcționeze, toate obiectele returnate trebuie să aibă o interfață comună. Subclasele vor putea produce obiecte din diferite clase care implementează această interfață.

De exemplu, clasele Truck și Car implementează interfața CourierTransport cu o metodă de livrare . Fiecare dintre aceste clase implementează metoda într-un mod diferit: camioanele livrează mărfuri, în timp ce mașinile livrează alimente, pachete și așa mai departe. Metoda fabrică din clasa TruckCreator returnează un obiect camion, iar clasa CarCreator returnează un obiect auto.

Pentru clientul metodei din fabrică, nu există nicio diferență între aceste obiecte, deoarece le va trata ca un fel de CourierTransport abstract . Clientului îi va păsa profund că obiectul are o metodă de livrare, dar modul în care funcționează exact acea metodă nu este important.

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

Dacă vrem să creăm un nou obiect de livrare, atunci programul creează automat un obiect de transport corespunzător.

Când ar trebui să aplicăm acest model?

1. Când nu cunoașteți dinainte tipurile și dependențele obiectelor cu care trebuie să lucreze codul dvs.

Metoda fabricii separă codul pentru producerea formelor de transport de codul care utilizează transportul. Drept urmare, codul pentru crearea obiectelor poate fi extins fără a atinge restul codului.

De exemplu, pentru a adăuga suport pentru un nou tip de transport, trebuie să creați o nouă subclasă și să definiți o metodă din fabrică în ea care returnează o instanță a noului transport.

2. Când doriți să economisiți resursele sistemului prin reutilizarea obiectelor existente în loc să creați altele noi.

Această problemă apare de obicei atunci când lucrați cu obiecte care necesită mult resurse, cum ar fi conexiuni la baze de date, sisteme de fișiere etc.

Gândiți-vă la pașii pe care trebuie să-i faceți pentru a reutiliza obiectele existente:

  1. Mai întâi, trebuie să creați un depozit partajat pentru a stoca toate obiectele pe care le creați.

  2. Când solicitați un obiect nou, trebuie să căutați în depozit și să verificați dacă acesta conține un obiect disponibil.

  3. Returnează obiectul la codul client.

  4. Dar dacă nu există obiecte disponibile, creați unul nou și adăugați-l în depozit.

Tot acest cod trebuie pus într-un loc care să nu aglomereze codul clientului. Cel mai convenabil loc ar fi constructorul, deoarece avem nevoie doar de toate aceste verificări atunci când creăm obiecte. Din păcate, un constructor creează întotdeauna un obiect nou - nu poate returna un obiect existent.

Aceasta înseamnă că este necesară o altă metodă care poate returna atât obiectele existente, cât și cele noi. Aceasta va fi metoda din fabrică.

3. Când doriți să permiteți utilizatorilor să extindă părți din cadrul sau din bibliotecă.

Utilizatorii vă pot extinde clasele cadru prin moștenire. Dar cum faci ca cadrul să creeze obiecte din aceste noi clase, mai degrabă decât cele standard?

Soluția este de a permite utilizatorilor să extindă nu numai componentele, ci și clasele care creează acele componente. Și pentru aceasta, clasele de creare trebuie să aibă metode de creare specifice care pot fi definite.

Avantaje

  • Decuplează o clasă de anumite clase de transport.
  • Păstrează codul pentru crearea formelor de transport într-un singur loc, făcând codul mai ușor de întreținut.
  • Simplifică adăugarea de noi moduri de transport la program.
  • Implementează principiul deschis-închis.

Dezavantaje

Poate duce la ierarhii mari de clase paralele, deoarece fiecare clasă de produse trebuie să aibă propria subclasă de creator.

Să rezumam

Ați aflat despre modelul metodei din fabrică și ați văzut o posibilă implementare. Acest model este adesea folosit în diferite biblioteci care oferă obiecte pentru crearea altor obiecte.

Utilizați modelul metodei din fabrică atunci când doriți să adăugați cu ușurință noi obiecte de subclase ale claselor existente pentru a interacționa cu logica principală de afaceri și pentru a nu vă umfla codul din cauza diferitelor contexte.