Hi! Ngayon ay patuloy nating pag-aaralan ang mga pattern ng disenyo at tatalakayin natin ang abstract factory pattern. Narito ang tatalakayin natin sa aralin:
- Tatalakayin natin kung ano ang abstract factory at kung anong problema ang nalulutas ng pattern na ito
- Gagawa kami ng skeleton ng isang cross-platform na application para sa pag-order ng kape sa pamamagitan ng user interface
- Pag-aaralan namin ang mga tagubilin kung paano gamitin ang pattern na ito, kabilang ang pagtingin sa isang diagram at code
- At bilang isang bonus, ang araling ito ay may kasamang isang nakatagong Easter egg na tutulong sa iyo na matutunan kung paano gamitin ang Java upang matukoy ang pangalan ng operating system at, depende sa resulta, upang magsagawa ng isa't isa na aksyon o iba pa.
- mana sa Java
- abstract na mga klase at pamamaraan sa Java
Anong mga problema ang nalulutas ng abstract factory?
Ang isang abstract na pabrika, tulad ng lahat ng mga pattern ng pabrika, ay tumutulong sa amin upang matiyak na ang mga bagong bagay na gagawin nang tama. Ginagamit namin ito upang pamahalaan ang "produksyon" ng iba't ibang pamilya ng magkakaugnay na mga bagay. Iba't ibang pamilya ng magkakaugnay na bagay... Ano ang ibig sabihin nito? Huwag mag-alala: sa pagsasagawa, ang lahat ay mas simple kaysa sa tila. Upang magsimula, ano ang maaaring maging isang pamilya ng magkakaugnay na mga bagay? Ipagpalagay na bubuo tayo ng diskarteng militar na kinasasangkutan ng ilang uri ng mga yunit:- impanterya
- kabalyerya
- mga mamamana
Ipagpatuloy natin ang pag-automate ng ating coffee shop
Sa huling aralin, pinag-aralan namin ang pattern ng factory method. Ginamit namin ito upang palawakin ang aming negosyo sa kape at magbukas ng ilang bagong lokasyon. Ngayon, patuloy nating gagawing moderno ang ating negosyo. Gamit ang abstract factory pattern, ilalagay namin ang pundasyon para sa isang bagong desktop application para sa pag-order ng kape online. Kapag nagsusulat ng isang desktop application, dapat nating palaging isipin ang tungkol sa cross-platform na suporta. Ang aming application ay dapat gumana sa parehong macOS at Windows (spoiler: Ang suporta para sa Linux ay natitira para sa iyo upang ipatupad bilang araling-bahay). Ano ang magiging hitsura ng aming aplikasyon? Medyo simple: ito ay magiging isang form na binubuo ng isang text field, isang selection field, at isang button. Kung mayroon kang karanasan sa paggamit ng iba't ibang mga operating system, tiyak na napansin mo na ang mga button sa Windows ay nai-render nang iba kaysa sa isang Mac. Tulad ng lahat ng iba pa... Well, magsimula tayo.- mga pindutan
- mga patlang ng teksto
- mga patlang ng pagpili
onClick
, onValueChanged
, o onInputChanged
. Sa madaling salita, maaari naming tukuyin ang mga pamamaraan na magpapahintulot sa amin na pangasiwaan ang iba't ibang mga kaganapan (pagpindot sa isang pindutan, pagpasok ng teksto, pagpili ng isang halaga sa isang kahon ng pagpili). Ang lahat ng ito ay sadyang tinanggal dito upang hindi ma-overload ang halimbawa at upang maging mas malinaw habang pinag-aaralan natin ang pattern ng pabrika. Tukuyin natin ang mga abstract na interface para sa ating mga produkto:
public interface Button {}
public interface Select {}
public interface TextField {}
Para sa bawat operating system, dapat tayong lumikha ng mga elemento ng interface sa istilo ng operating system. Magsusulat kami ng code para sa Windows at MacOS. Gumawa tayo ng mga pagpapatupad para sa Windows:
public class WindowsButton implements Button {
}
public class WindowsSelect implements Select {
}
public class WindowsTextField implements TextField {
}
Ngayon ginagawa namin ang parehong para sa MacOS:
public class MacButton implements Button {
}
public class MacSelect implements Select {
}
public class MacTextField implements TextField {
}
Magaling. Ngayon ay maaari na tayong magpatuloy sa aming abstract factory, na gagawa ng lahat ng available na abstract na uri ng produkto:
public interface GUIFactory {
Button createButton();
TextField createTextField();
Select createSelect();
}
Napakagaling. Tulad ng nakikita mo, wala pa kaming ginagawang kumplikado. Ang lahat ng sumusunod ay simple din. Sa pamamagitan ng pagkakatulad sa mga produkto, lumikha kami ng iba't ibang mga pagpapatupad ng pabrika para sa bawat OS. Magsimula tayo sa 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();
}
}
Nagdagdag kami ng ilang console output sa loob ng mga pamamaraan at constructor upang higit pang mailarawan kung ano ang nangyayari. Ngayon para sa 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();
}
}
Tandaan na ang bawat lagda ng pamamaraan ay nagpapahiwatig na ang pamamaraan ay nagbabalik ng isang abstract na uri. Ngunit sa loob ng mga pamamaraan, gumagawa kami ng mga partikular na pagpapatupad ng mga produkto. Ito ang tanging lugar na kinokontrol namin ang paglikha ng mga partikular na pagkakataon. Ngayon ay oras na upang magsulat ng isang klase para sa form. Ito ay isang klase ng Java na ang mga patlang ay mga elemento ng interface:
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();
}
}
Ang abstract factory na lumilikha ng mga elemento ng interface ay ipinapasa sa constructor ng form. Ipapasa namin ang kinakailangang pagpapatupad ng pabrika sa constructor upang makalikha ng mga elemento ng interface para sa isang partikular na 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();
}
}
Kung patakbuhin namin ang application sa Windows, makukuha namin ang sumusunod na 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
Sa isang Mac, ang output ay ang mga sumusunod:
Creating GUIFactory for macOS
Creating coffee order form
Creating TextField for macOS
Creating Select for macOS
Creating Button for macOS
Sa Linux:
Unknown OS. Unable to draw form :(
At ngayon ay nagbubuod tayo. Isinulat namin ang skeleton ng isang GUI-based na application kung saan ang mga elemento ng interface ay partikular na nilikha para sa nauugnay na OS. Ulitin namin nang maikli ang aming nilikha:
- Isang pangkat ng produkto na binubuo ng isang input field, isang selection field, at isang button.
- Iba't ibang pagpapatupad ng pamilya ng produkto para sa Windows at macOS.
- Isang abstract na pabrika na tumutukoy sa isang interface para sa paggawa ng aming mga produkto.
- Dalawang pagpapatupad ng aming pabrika, bawat isa ay may pananagutan sa paglikha ng isang partikular na pamilya ng mga produkto.
- Isang form (isang Java class) na ang mga field ay abstract na mga elemento ng interface na sinisimulan gamit ang mga kinakailangang value sa constructor gamit ang abstract factory.
- Klase ng aplikasyon Sa loob ng klase na ito, lumikha kami ng isang form, na ipinapasa ang nais na pagpapatupad ng pabrika sa tagabuo nito.
Abstract factory: kung paano gamitin
Ang abstract factory ay isang pattern ng disenyo para sa pamamahala ng paglikha ng iba't ibang pamilya ng produkto nang hindi nakatali sa mga kongkretong klase ng produkto. Kapag ginagamit ang pattern na ito, dapat mong:- Tukuyin ang mga pamilya ng produkto. Ipagpalagay na mayroon tayong dalawa sa kanila:
SpecificProductA1
,SpecificProductB1
SpecificProductA2
,SpecificProductB2
- Para sa bawat produkto sa loob ng pamilya, tumukoy ng abstract na klase (interface). Sa aming kaso, mayroon kaming:
ProductA
ProductB
- Sa loob ng bawat pamilya ng produkto, dapat ipatupad ng bawat produkto ang interface na tinukoy sa hakbang 2.
- Lumikha ng abstract na pabrika, na may mga pamamaraan para sa paglikha ng bawat produkto na tinukoy sa hakbang 2. Sa aming kaso, ang mga pamamaraang ito ay magiging:
ProductA createProductA();
ProductB createProductB();
- Gumawa ng abstract na mga pagpapatupad ng pabrika upang kontrolin ng bawat pagpapatupad ang paglikha ng mga produkto ng isang pamilya. Upang gawin ito, sa loob ng bawat pagpapatupad ng abstract na pabrika, kailangan mong ipatupad ang lahat ng mga pamamaraan ng paglikha upang lumikha at magbalik sila ng mga partikular na pagpapatupad ng produkto.
// 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();
}
}
Takdang aralin
Upang palakasin ang materyal, maaari kang gumawa ng 2 bagay:- Pinuhin ang application ng pag-order ng kape upang gumana rin ito sa Linux.
- Lumikha ng iyong sariling abstract na pabrika para sa paggawa ng mga yunit na kasangkot sa anumang diskarte sa militar. Maaari itong maging isang makasaysayang diskarte sa militar na kinasasangkutan ng mga tunay na hukbo, o isang pantasya na may mga orc, gnome, at duwende. Ang mahalagang bagay ay pumili ng isang bagay na interesado ka. Maging malikhain, mag-print ng mga mensahe sa console, at mag-enjoy sa pag-aaral tungkol sa mga pattern!
GO TO FULL VERSION