Bună! Astăzi vom continua să studiem modelele de design și vom discuta despre modelul abstract din fabrică . Iată ce vom trata în lecție:
- Vom discuta ce este o fabrică abstractă și ce problemă rezolvă acest model
- Vom crea scheletul unei aplicații multiplatforme pentru a comanda cafea printr-o interfață de utilizator
- Vom studia instrucțiunile despre cum să folosiți acest model, inclusiv să examinăm o diagramă și un cod
- Și ca bonus, această lecție include un ou de Paște ascuns care vă va ajuta să învățați cum să utilizați Java pentru a determina numele sistemului de operare și, în funcție de rezultat, să efectuați unul sau altul.
- moștenire în Java
- clase și metode abstracte în Java
Ce probleme rezolvă o fabrică abstractă?
O fabrică abstractă, ca toate modelele de fabrică, ne ajută să ne asigurăm că obiectele noi vor fi create corect. Îl folosim pentru a gestiona „producția” diferitelor familii de obiecte interconectate. Diverse familii de obiecte interconectate... Ce înseamnă asta? Nu vă faceți griji: în practică, totul este mai simplu decât ar părea. Pentru început, ce ar putea fi o familie de obiecte interconectate? Să presupunem că dezvoltăm o strategie militară care implică mai multe tipuri de unități:- infanterie
- cavalerie
- arcașii
Să continuăm automatizarea cafenelei noastre
În ultima lecție, am studiat modelul metodei din fabrică. L-am folosit pentru a ne extinde afacerea cu cafea și a deschide mai multe locații noi. Astăzi vom continua să ne modernizăm afacerea. Folosind modelul abstract din fabrică, vom pune bazele unei noi aplicații desktop pentru comanda online de cafea. Când scriem o aplicație desktop, ar trebui să ne gândim întotdeauna la suportul pe mai multe platforme. Aplicația noastră trebuie să funcționeze atât pe macOS, cât și pe Windows (spoiler: Suportul pentru Linux este lăsat pentru implementare ca teme). Cum va arăta aplicația noastră? Destul de simplu: va fi un formular format dintr-un câmp de text, un câmp de selecție și un buton. Dacă aveți experiență în utilizarea diferitelor sisteme de operare, cu siguranță ați observat că butoanele Windows sunt redate diferit decât pe un Mac. Ca și orice altceva... Ei bine, să începem.- butoane
- câmpuri de text
- câmpuri de selecție
onClick
, onValueChanged
, sau onInputChanged
. Cu alte cuvinte, am putea defini metode care ne vor permite să gestionăm diverse evenimente (apăsarea unui buton, introducerea textului, selectarea unei valori într-o casetă de selecție). Toate acestea sunt omise aici în mod deliberat pentru a nu supraîncărca exemplul și pentru a-l face mai clar pe măsură ce studiem modelul din fabrică. Să definim interfețe abstracte pentru produsele noastre:
public interface Button {}
public interface Select {}
public interface TextField {}
Pentru fiecare sistem de operare, trebuie să creăm elemente de interfață în stilul sistemului de operare. Vom scrie cod pentru Windows și MacOS. Să creăm implementări pentru Windows:
public class WindowsButton implements Button {
}
public class WindowsSelect implements Select {
}
public class WindowsTextField implements TextField {
}
Acum facem același lucru pentru MacOS:
public class MacButton implements Button {
}
public class MacSelect implements Select {
}
public class MacTextField implements TextField {
}
Excelent. Acum putem trece la fabrica noastră de abstracte, care va crea toate tipurile de produse abstracte disponibile:
public interface GUIFactory {
Button createButton();
TextField createTextField();
Select createSelect();
}
Superb. După cum puteți vedea, încă nu am făcut nimic complicat. Tot ce urmează este, de asemenea, simplu. Prin analogie cu produsele, creăm diverse implementări din fabrică pentru fiecare sistem de operare. Să începem cu Windows:
public class WindowsGUIFactory implements GUIFactory {
public WindowsGUIFactory() {
System.out.println("Creating GUIFactory for Windows OS");
}
public Button createButton() {
System.out.println("Creating Button for Windows OS");
return new WindowsButton();
}
public TextField createTextField() {
System.out.println("Creating TextField for Windows OS");
return new WindowsTextField();
}
public Select createSelect() {
System.out.println("Creating Select for Windows OS");
return new WindowsSelect();
}
}
Am adăugat o ieșire de consolă în cadrul metodelor și al constructorului pentru a ilustra în continuare ceea ce se întâmplă. Acum pentru macOS:
public class MacGUIFactory implements GUIFactory {
public MacGUIFactory() {
System.out.println("Creating GUIFactory for macOS");
}
@Override
public Button createButton() {
System.out.println("Creating Button for macOS");
return new MacButton();
}
@Override
public TextField createTextField() {
System.out.println("Creating TextField for macOS");
return new MacTextField();
}
@Override
public Select createSelect() {
System.out.println("Creating Select for macOS");
return new MacSelect();
}
}
Rețineți că fiecare semnătură de metodă indică faptul că metoda returnează un tip abstract. Dar în cadrul metodelor, creăm implementări specifice ale produselor. Acesta este singurul loc în care controlăm crearea unor instanțe specifice. Acum este timpul să scrieți o clasă pentru formular. Aceasta este o clasă Java ale cărei câmpuri sunt elemente de interfață:
public class CoffeeOrderForm {
private final TextField customerNameTextField;
private final Select coffeeTypeSelect;
private final Button orderButton;
public CoffeeOrderForm(GUIFactory factory) {
System.out.println("Creating coffee order form");
customerNameTextField = factory.createTextField();
coffeeTypeSelect = factory.createSelect();
orderButton = factory.createButton();
}
}
O fabrică abstractă care creează elemente de interfață este transmisă constructorului formularului. Vom trece implementarea din fabrică necesară constructorului pentru a crea elemente de interfață pentru un anumit sistem de operare.
public class Application {
private CoffeeOrderForm coffeeOrderForm;
public void drawCoffeeOrderForm() {
// Determine the name of the operating system through System.getProperty()
String osName = System.getProperty("os.name").toLowerCase();
GUIFactory guiFactory;
if (osName.startsWith("win")) { // For Windows
guiFactory = new WindowsGUIFactory();
} else if (osName.startsWith("mac")) { // For Mac
guiFactory = new MacGUIFactory();
} else {
System.out.println("Unknown OS. Unable to draw form :(");
return;
}
coffeeOrderForm = new CoffeeOrderForm(guiFactory);
}
public static void main(String[] args) {
Application application = new Application();
application.drawCoffeeOrderForm();
}
}
Dacă rulăm aplicația pe Windows, obținem următoarea ieșire:
Creating GUIFactory for Windows OS
Creating coffee order form
Creating TextField for Windows OS
Creating Select for Windows OS
Creating Button for Windows OS
Pe un Mac, rezultatul va fi după cum urmează:
Creating GUIFactory for macOS
Creating coffee order form
Creating TextField for macOS
Creating Select for macOS
Creating Button for macOS
Pe Linux:
Unknown OS. Unable to draw form :(
Și acum rezumăm. Am scris scheletul unei aplicații bazate pe GUI în care elementele de interfață sunt create special pentru sistemul de operare relevant. Vom repeta concis ceea ce am creat:
- O familie de produse formată dintr-un câmp de introducere, un câmp de selecție și un buton.
- Diferite implementări ale familiei de produse pentru Windows și macOS.
- O fabrică abstractă care definește o interfață pentru crearea produselor noastre.
- Două implementări ale fabricii noastre, fiecare responsabilă pentru crearea unei familii specifice de produse.
- Un formular (o clasă Java) ale cărui câmpuri sunt elemente abstracte de interfață care sunt inițializate cu valorile necesare în constructor folosind o fabrică abstractă.
- Clasa de aplicație În cadrul acestei clase, creăm un formular, trecând implementarea din fabrică dorită constructorului său.
Fabrica de abstracte: cum se utilizează
O fabrică abstractă este un model de design pentru gestionarea creării diferitelor familii de produse fără a fi legată de clase de produse concrete. Când utilizați acest model, trebuie să:- Definiți familiile de produse. Să presupunem că avem două dintre ele:
SpecificProductA1
,SpecificProductB1
SpecificProductA2
,SpecificProductB2
- Pentru fiecare produs din familie, definiți o clasă abstractă (interfață). În cazul nostru avem:
ProductA
ProductB
- În cadrul fiecărei familii de produse, fiecare produs trebuie să implementeze interfața definită la pasul 2.
- Creați o fabrică abstractă, cu metode de creare a fiecărui produs definite la pasul 2. În cazul nostru, aceste metode vor fi:
ProductA createProductA();
ProductB createProductB();
- Creați implementări abstracte din fabrică, astfel încât fiecare implementare să controleze crearea de produse dintr-o singură familie. Pentru a face acest lucru, în cadrul fiecărei implementări a fabricii abstracte, trebuie să implementați toate metodele de creații, astfel încât acestea să creeze și să returneze implementări specifice de produs.
// Define common product interfaces
public interface ProductA {}
public interface ProductB {}
// Create various implementations (families) of our products
public class SpecificProductA1 implements ProductA {}
public class SpecificProductB1 implements ProductB {}
public class SpecificProductA2 implements ProductA {}
public class SpecificProductB2 implements ProductB {}
// Create an abstract factory
public interface AbstractFactory {
ProductA createProductA();
ProductB createProductB();
}
// Implement the abstract factory in order to create products in family 1
public class SpecificFactory1 implements AbstractFactory {
@Override
public ProductA createProductA() {
return new SpecificProductA1();
}
@Override
public ProductB createProductB() {
return new SpecificProductB1();
}
}
// Implement the abstract factory in order to create products in family 2
public class SpecificFactory2 implements AbstractFactory {
@Override
public ProductA createProductA() {
return new SpecificProductA2();
}
@Override
public ProductB createProductB() {
return new SpecificProductB2();
}
}
Teme pentru acasă
Pentru a consolida materialul, puteți face 2 lucruri:- Rafinați aplicația de comandă de cafea, astfel încât să funcționeze și pe Linux.
- Creează-ți propria fabrică abstractă pentru a produce unități implicate în orice strategie militară. Aceasta poate fi fie o strategie militară istorică care implică armate reale, fie una fantastică cu orci, gnomi și elfi. Important este să alegi ceva care te interesează. Fiți creativ, imprimați mesaje pe consolă și bucurați-vă de a afla despre modele!
GO TO FULL VERSION