JavaRush /Java Blog /Random-TL /Mga Pattern ng Disenyo: AbstractFactory

Mga Pattern ng Disenyo: AbstractFactory

Nai-publish sa grupo
Kamusta! Ngayon ay patuloy nating pag-aaralan ang mga pattern ng disenyo at pag-uusapan ang abstract factory . Mga Pattern ng Disenyo: AbstractFactory - 1Ano ang gagawin natin sa lecture:
  • Talakayin natin kung ano ang abstract factory at kung anong problema ang nalulutas ng pattern na ito;
  • gagawa kami ng balangkas ng isang cross-platform na application para sa pag-order ng kape na may user interface;
  • Pag-aralan natin ang mga tagubilin para sa paggamit ng pattern na ito na may diagram at code;
  • Bilang isang bonus, mayroong isang Easter egg na nakatago sa lecture, salamat sa kung saan matututunan mong matukoy ang pangalan ng operating system gamit ang Java at, depende sa resulta, magsagawa ng isa o isa pang aksyon.
Upang lubos na maunawaan ang pattern na ito, kailangan mong magkaroon ng mahusay na pag-unawa sa mga sumusunod na paksa:
  • mana sa Java;
  • abstract na mga klase at pamamaraan sa Java.

Anong mga problema ang nalulutas ng abstract factory pattern?

Ang abstract na pabrika, tulad ng lahat ng mga pattern ng pabrika, ay tumutulong sa amin na ayusin ang paglikha ng mga bagong bagay nang tama. Sa tulong nito, pinamamahalaan namin ang "paglabas" ng iba't ibang pamilya ng magkakaugnay na mga bagay. Iba't ibang pamilya ng magkakaugnay na bagay...Ano ito? Huwag mag-alala: sa pagsasagawa, ang lahat ay mas simple kaysa sa tila. Magsimula tayo sa kung ano ang maaaring isang pamilya ng mga kaugnay na bagay? Ipagpalagay na ikaw at ako ay bumubuo ng isang diskarte, at mayroong ilang mga yunit ng labanan sa loob nito:
  • impanterya;
  • kabalyerya;
  • mga mamamana.
Ang mga uri ng mga yunit ng labanan ay may kaugnayan sa bawat isa, dahil sila ay naglilingkod sa parehong hukbo. Masasabi nating ang mga kategoryang nakalista sa itaas ay isang pamilya ng magkakaugnay na mga bagay. Naayos na yan. Ngunit ang abstract na pattern ng pabrika ay ginagamit upang ayusin ang paglikha ng iba't ibang mga pamilya ng magkakaugnay na mga bagay. Wala ring kumplikado dito. Ipagpatuloy natin ang halimbawa sa diskarte. Karaniwan silang may iba't ibang magkasalungat na panig. Ang mga yunit ng labanan ng iba't ibang panig ay maaaring magkaiba nang malaki sa hitsura. Ang mga kawal, mangangabayo at mamamana ng hukbong Romano ay hindi katulad ng mga kawal, mangangabayo at mamamana ng mga Viking. Sa loob ng balangkas ng diskarte, ang mga sundalo ng iba't ibang hukbo ay magkakaibang pamilya ng magkakaugnay na mga bagay. Ito ay magiging nakakatawa kung, sa pamamagitan ng pagkakamali ng isang programmer, isang sundalo sa isang Pranses na uniporme mula sa panahon ni Napoleon, na may isang musket na handa, ay naglalakad sa paligid ng Roman infantry. Ito ay upang malutas ang gayong problema na kailangan ang abstract na pattern ng disenyo ng pabrika. Hindi, hindi ang mga problema ng time travel kahihiyan, ngunit ang paglikha ng iba't ibang mga grupo ng mga interconnected na bagay. Ang abstract factory ay nagbibigay ng isang interface para sa paglikha ng lahat ng umiiral na mga produkto (mga bagay sa pamilya). Karaniwang mayroong maraming pagpapatupad ang abstract factory. Ang bawat isa sa kanila ay may pananagutan sa paglikha ng mga produkto ng isa sa mga pagkakaiba-iba. Bilang bahagi ng diskarte, magkakaroon tayo ng abstract factory na lumilikha ng abstract infantry, archers at cavalry, pati na rin ang mga pagpapatupad ng factory na ito. Isang pabrika na lumilikha ng mga Romanong legionnaire at, halimbawa, isang pabrika na lumilikha ng mga mandirigmang Carthaginian. Ang abstraction ay ang pinakamahalagang prinsipyo ng pattern na ito. Ang mga kliyente ng pabrika ay nagtatrabaho dito at sa mga produkto lamang sa pamamagitan ng mga abstract na interface. Samakatuwid, hindi natin kailangang isipin kung anong uri ng mga mandirigma ang kasalukuyang ginagawa natin, ngunit ilipat ang responsibilidad na ito sa ilang partikular na pagpapatupad ng abstract factory.

Patuloy naming ginagawang awtomatiko ang coffee shop

Sa huling panayam, pinag-aralan namin ang pattern ng factory method, sa tulong kung saan napalawak namin ang negosyo ng kape at nagbukas ng ilang mga bagong punto ng pagbebenta ng kape. Ngayon ay ipagpapatuloy natin ang ating gawain para gawing 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 sumulat tayo ng isang application para sa desktop, dapat nating palaging isipin ang tungkol sa cross-platform. Ang aming application ay dapat gumana sa parehong macOS at Windows (spoiler: Ang Linux ay iiwan para sa iyo bilang araling-bahay). Ano ang magiging hitsura ng aming aplikasyon? Medyo simple: ito ay magiging isang form na binubuo ng isang text field, isang piling field, at isang button. Kung mayroon kang karanasan sa paggamit ng iba't ibang mga operating system, tiyak na napansin mo na sa Windows ang mga pindutan ay nai-render nang iba kaysa sa Mac. Tulad ng lahat ng iba pa... Kaya, magsimula tayo. Sa papel ng mga pamilya ng produkto, tulad ng malamang na naunawaan mo na, magkakaroon kami ng mga elemento ng graphical na interface:
  • mga pindutan;
  • mga patlang ng teksto;
  • mga patlang para sa pagpili.
Disclaimer. Sa loob ng bawat interface maaari naming tukuyin ang mga pamamaraan tulad ng onClick, onValueChangedo onInputChanged. Yung. mga pamamaraan na magpapahintulot sa amin na pangasiwaan ang iba't ibang mga kaganapan (pag-click sa isang pindutan, pagpasok ng teksto, pagpili ng isang halaga sa isang piling kahon). Ang lahat ng ito ay sadyang tinanggal upang hindi ma-overload ang halimbawa at gawin itong mas visual para sa pag-aaral ng 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 na iyon. Nagsusulat kami 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 ay pareho para sa MacOS:
public class MacButton implements Button {
}

public class MacSelect implements Select {
}

public class MacTextField implements TextField {
}
Malaki. Ngayon ay maaari na nating simulan ang aming abstract factory, na lilikha ng lahat ng umiiral na abstract na uri ng produkto:
public interface GUIFactory {

    Button createButton();
    TextField createTextField();
    Select createSelect();

}
Perpekto. Tulad ng nakikita mo, walang kumplikado sa ngayon. Kung gayon ang lahat ay kasing simple. Sa pamamagitan ng pagkakatulad sa mga produkto, gumagawa kami ng iba't ibang pagpapatupad ng aming pabrika para sa bawat OS. Magsimula tayo sa Windows:
public class WindowsGUIFactory implements GUIFactory {
    public WindowsGUIFactory() {
        System.out.println("Creating gui factory 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();
    }
}
Ang output ng console sa loob ng mga pamamaraan at constructor ay idinagdag upang higit pang ipakita kung paano ito gumagana. Ngayon para sa macOS:
public class MacGUIFactory implements GUIFactory {
    public MacGUIFactory() {
        System.out.println("Creating gui factory 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: ang bawat pamamaraan, ayon sa lagda nito, ay nagbabalik ng abstract na uri. Ngunit sa loob ng pamamaraan ay lumikha kami ng isang kongkretong pagpapatupad ng produkto. Ito ang tanging lugar kung saan kinokontrol namin ang paglikha ng mga partikular na pagkakataon. Ngayon ay oras na upang isulat ang klase ng form. Ito ay isang klase ng Java na ang mga patlang ay mga elemento ng interface:
public class OrderCoffeeForm {
    private final TextField customerNameTextField;
    private final Select coffeTypeSelect;
    private final Button orderButton;

    public OrderCoffeeForm(GUIFactory factory) {
        System.out.println("Creating order coffee form");
        customerNameTextField = factory.createTextField();
        coffeTypeSelect = factory.createSelect();
        orderButton = factory.createButton();
    }
}
Ang abstract factory ay ipinapasa sa form constructor, na lumilikha ng mga elemento ng interface. Ipapasa namin ang kinakailangang pagpapatupad ng pabrika sa constructor upang makagawa kami ng mga elemento ng interface para sa isang partikular na OS.
public class Application {
    private OrderCoffeeForm orderCoffeeForm;

    public void drawOrderCoffeeForm() {
        // Определим Name операционной системы, получив meaning системной проперти через System.getProperty
        String osName = System.getProperty("os.name").toLowerCase();
        GUIFactory guiFactory;

        if (osName.startsWith("win")) { // Для windows
            guiFactory = new WindowsGUIFactory();
        } else if (osName.startsWith("mac")) { // Для mac
            guiFactory = new MacGUIFactory();
        } else {
            System.out.println("Unknown OS, can't draw form :( ");
            return;
        }
        orderCoffeeForm = new OrderCoffeeForm(guiFactory);
    }

    public static void main(String[] args) {
        Application application = new Application();
        application.drawOrderCoffeeForm();
    }
}
Kung patakbuhin namin ang application sa Windows, makukuha namin ang sumusunod na output:

Creating gui factory for Windows OS
Creating order coffee form
Creating TextField for Windows OS
Creating Select for Windows OS
Creating Button for Windows OS
Sa isang Mac ang output ay magiging tulad ng sumusunod:

Creating gui factory for macOS
Creating order coffee form
Creating TextField for macOS
Creating Select for macOS
Creating Button for macOS
Sa Linux:

Unknown OS, can't draw form :( 
Buweno, ikaw at ako ay gumuhit ng sumusunod na konklusyon. Sumulat kami ng isang framework para sa isang GUI application na lumilikha ng eksaktong mga elemento ng interface na naaangkop para sa isang partikular na OS. Ulitin natin sandali ang ating nilikha:
  • Pamilya ng produkto: field ng input, field ng pagpili at button.
  • Iba't ibang pagpapatupad ng pamilyang ito ng mga produkto, para sa Windows at macOS.
  • Isang abstract factory, kung saan tinukoy namin ang 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 klase ng Java na ang mga field ay abstract na mga elemento ng interface na sinisimulan sa constructor na may mga kinakailangang halaga gamit ang abstract factory.
  • Klase ng aplikasyon. Sa loob nito, lumikha kami ng isang form kung saan ipinapasa namin ang kinakailangang pagpapatupad ng aming pabrika sa tagabuo.
Kabuuan: ipinatupad namin ang abstract factory pattern.

Abstract Factory: mga tagubilin para sa paggamit

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 partikular na klase ng produkto. Kapag ginagamit ang template na ito, dapat mong:
  1. Tukuyin ang mga pamilya ng produkto mismo. Ipagpalagay natin na mayroon tayong dalawa sa kanila:
    • SpecificProductA1,SpecificProductB1
    • SpecificProductA2,SpecificProductB2
  2. Para sa bawat produkto sa loob ng pamilya, tumukoy ng abstract na klase (interface). Sa aming kaso ito ay:
    • ProductA
    • ProductB
  3. Sa loob ng bawat pamilya ng produkto, dapat ipatupad ng bawat produkto ang interface na tinukoy sa hakbang 2.
  4. Lumikha ng abstract factory, na may mga paraan ng paggawa para sa bawat produkto na tinukoy sa hakbang 2. Sa aming kaso, ang mga paraang ito ay:
    • ProductA createProductA();
    • ProductB createProductB();
  5. Gumawa ng mga pagpapatupad ng abstract factory upang kontrolin ng bawat pagpapatupad ang paglikha ng mga produkto ng parehong pamilya. Upang gawin ito, sa loob ng bawat pagpapatupad ng abstract na pabrika, kinakailangan na ipatupad ang lahat ng mga pamamaraan ng paglikha, upang ang mga kongkretong pagpapatupad ng mga produkto ay nilikha at ibinalik sa loob ng mga ito.
Nasa ibaba ang isang diagram ng UML na naglalarawan ng mga tagubiling inilarawan sa itaas: Mga Pattern ng Disenyo: AbstractFactory - 3Ngayon ay isulat natin ang code para sa pagtuturo na ito:
// Определим общие интерфейсы продуктов
public interface ProductA {}
public interface ProductB {}

// Создадим различные реализации (семейства) наших продуктов
public class SpecificProductA1 implements ProductA {}
public class SpecificProductB1 implements ProductB {}

public class SpecificProductA2 implements ProductA {}
public class SpecificProductB2 implements ProductB {}

// Создадим абстрактную фабрику
public interface AbstractFactory {
    ProductA createProductA();
    ProductB createProductB();
}

// Создадим реализацию абстрактной фабрики для создания продуктов семейства 1
public class SpecificFactory1 implements AbstractFactory {

    @Override
    public ProductA createProductA() {
        return new SpecificProductA1();
    }

    @Override
    public ProductB createProductB() {
        return new SpecificProductB1();
    }
}

// Создадим реализацию абстрактной фабрики для создания продуктов семейства 1
public class SpecificFactory2 implements AbstractFactory {

    @Override
    public ProductA createProductA() {
        return new SpecificProductA2();
    }

    @Override
    public ProductB createProductB() {
        return new SpecificProductB2();
    }
}

Takdang aralin

Upang pagsamahin ang materyal maaari kang gumawa ng 2 bagay:
  1. Pagbutihin ang application ng pag-order ng kape upang gumana ito sa Linux.
  2. Lumikha ng iyong sariling abstract na pabrika upang makagawa ng mga yunit ng anumang diskarte. Maaari itong maging isang makasaysayang diskarte sa mga tunay na hukbo o isang pantasya sa mga orc, dwarf at duwende. Ang pangunahing bagay ay nahanap mo itong kawili-wili. Maging malikhain, mag-post ng mga pin sa console, at magsaya sa pag-aaral ng mga pattern!
Mga komento
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION