Hej! I dag vil vi fortsætte med at studere designmønstre, og vi vil diskutere det abstrakte fabriksmønster .
Her er, hvad vi vil dække i lektionen:
Nu vil vi skrive kode i henhold til disse instruktioner:

- Vi vil diskutere, hvad en abstrakt fabrik er, og hvilket problem dette mønster løser
- Vi vil skabe skelettet af en applikation på tværs af platforme til bestilling af kaffe gennem en brugergrænseflade
- Vi vil studere instruktioner om, hvordan man bruger dette mønster, herunder at se på et diagram og en kode
- Og som en bonus inkluderer denne lektion et skjult påskeæg, der vil hjælpe dig med at lære, hvordan du bruger Java til at bestemme navnet på operativsystemet og, afhængigt af resultatet, udføre en anden handling eller en anden.
- arv i Java
- abstrakte klasser og metoder i Java
Hvilke problemer løser en abstrakt fabrik?
En abstrakt fabrik, som alle fabriksmønstre, hjælper os med at sikre, at nye objekter bliver skabt korrekt. Vi bruger det til at styre "produktionen" af forskellige familier af indbyrdes forbundne objekter. Forskellige familier af indbyrdes forbundne objekter... Hvad betyder det? Bare rolig: i praksis er alt enklere, end det ser ud til. Til at begynde med, hvad kunne en familie af indbyrdes forbundne objekter være? Antag, at vi udvikler en militærstrategi, der involverer flere typer enheder:- infanteri
- kavaleri
- bueskytter
Lad os fortsætte med at automatisere vores kaffebar
I sidste lektion, studerede vi fabrikkens metodemønster. Vi brugte det til at udvide vores kaffeforretning og åbne flere nye lokationer. I dag fortsætter vi med at modernisere vores forretning. Ved hjælp af det abstrakte fabriksmønster vil vi lægge grundlaget for en ny desktopapplikation til bestilling af kaffe online. Når vi skriver en desktopapplikation, bør vi altid tænke på support på tværs af platforme. Vores applikation skal fungere på både macOS og Windows (spoiler: Support til Linux er overladt til dig at implementere som hjemmearbejde). Hvordan vil vores ansøgning se ud? Ret simpelt: det vil være en formular, der består af et tekstfelt, et valgfelt og en knap. Hvis du har erfaring med at bruge forskellige operativsystemer, har du helt sikkert bemærket, at knapper på Windows er gengivet anderledes end på en Mac. Som alt andet er... Nå, lad os begynde.- knapper
- tekstfelter
- udvælgelsesfelter
onClick
, onValueChanged
, eller onInputChanged
. Med andre ord kunne vi definere metoder, der giver os mulighed for at håndtere forskellige begivenheder (tryk på en knap, indtastning af tekst, valg af en værdi i en valgboks). Alt dette er bevidst udeladt her for ikke at overbelaste eksemplet og for at gøre det tydeligere, mens vi studerer fabriksmønsteret. Lad os definere abstrakte grænseflader for vores produkter:
public interface Button {}
public interface Select {}
public interface TextField {}
For hvert operativsystem skal vi oprette grænsefladeelementer i stil med operativsystemet. Vi skriver kode til Windows og MacOS. Lad os lave implementeringer til Windows:
public class WindowsButton implements Button {
}
public class WindowsSelect implements Select {
}
public class WindowsTextField implements TextField {
}
Nu gør vi det samme for MacOS:
public class MacButton implements Button {
}
public class MacSelect implements Select {
}
public class MacTextField implements TextField {
}
Fremragende. Nu kan vi fortsætte til vores abstrakte fabrik, som vil skabe alle tilgængelige abstrakte produkttyper:
public interface GUIFactory {
Button createButton();
TextField createTextField();
Select createSelect();
}
Fantastisk. Som du kan se, har vi ikke gjort noget kompliceret endnu. Alt, hvad der følger, er også enkelt. Analogt med produkterne skaber vi forskellige fabriksimplementeringer for hvert OS. Lad os starte med 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();
}
}
Vi har tilføjet noget konsoloutput inde i metoderne og konstruktøren for yderligere at illustrere, hvad der sker. Nu til 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();
}
}
Bemærk, at hver metodesignatur angiver, at metoden returnerer en abstrakt type. Men inde i metoderne skaber vi specifikke implementeringer af produkterne. Dette er det eneste sted, hvor vi kontrollerer oprettelsen af specifikke forekomster. Nu er det tid til at skrive en klasse til formularen. Dette er en Java-klasse, hvis felter er grænsefladeelementer:
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();
}
}
En abstrakt fabrik, der skaber grænsefladeelementer, videregives til formularens konstruktør. Vi vil videregive den nødvendige fabriksimplementering til konstruktøren for at skabe grænsefladeelementer til et bestemt OS.
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();
}
}
Hvis vi kører programmet på Windows, får vi følgende output:
Creating GUIFactory for Windows OS
Creating coffee order form
Creating TextField for Windows OS
Creating Select for Windows OS
Creating Button for Windows OS
På en Mac vil outputtet være som følger:
Creating GUIFactory for macOS
Creating coffee order form
Creating TextField for macOS
Creating Select for macOS
Creating Button for macOS
På Linux:
Unknown OS. Unable to draw form :(
Og nu opsummerer vi. Vi skrev skelettet af en GUI-baseret applikation, hvor grænsefladeelementerne er skabt specifikt til det relevante OS. Vi gentager kortfattet, hvad vi har lavet:
- En produktfamilie bestående af et inputfelt, et valgfelt og en knap.
- Forskellige implementeringer af produktfamilien til Windows og macOS.
- En abstrakt fabrik, der definerer en grænseflade til at skabe vores produkter.
- To implementeringer af vores fabrik, hver ansvarlig for at skabe en bestemt familie af produkter.
- En formular (en Java-klasse), hvis felter er abstrakte grænsefladeelementer, der initialiseres med de nødvendige værdier i konstruktøren ved hjælp af en abstrakt fabrik.
- Applikationsklasse Inde i denne klasse opretter vi en formular, der sender den ønskede fabriksimplementering til dens konstruktør.
Abstrakt fabrik: hvordan man bruger
En abstrakt fabrik er et designmønster til styring af skabelsen af forskellige produktfamilier uden at være bundet til konkrete produktklasser. Når du bruger dette mønster, skal du:- Definer produktfamilier. Antag, at vi har to af dem:
SpecificProductA1
,SpecificProductB1
SpecificProductA2
,SpecificProductB2
- For hvert produkt i familien skal du definere en abstrakt klasse (grænseflade). I vores tilfælde har vi:
ProductA
ProductB
- Inden for hver produktfamilie skal hvert produkt implementere den grænseflade, der er defineret i trin 2.
- Opret en abstrakt fabrik med metoder til at skabe hvert produkt defineret i trin 2. I vores tilfælde vil disse metoder være:
ProductA createProductA();
ProductB createProductB();
- Opret abstrakte fabriksimplementeringer, så hver implementering styrer oprettelsen af produkter fra en enkelt familie. For at gøre dette skal du inde i hver implementering af den abstrakte fabrik implementere alle skabelsesmetoder, så de skaber og returnerer specifikke produktimplementeringer.

// 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();
}
}
Lektier
For at forstærke materialet kan du gøre 2 ting:- Forfin kaffebestillingsapplikationen, så den også fungerer på Linux.
- Skab din egen abstrakte fabrik til at producere enheder involveret i enhver militær strategi. Dette kan enten være en historisk militærstrategi, der involverer rigtige hære, eller en fantasistrategi med orker, nisser og elvere. Det vigtige er at vælge noget, der interesserer dig. Vær kreativ, udskriv beskeder på konsollen, og nyd at lære om mønstre!
GO TO FULL VERSION