CodeGym/Blog Java/Aleatoriu/Modele de design: Fabrică abstractă
John Squirrels
Nivel
San Francisco

Modele de design: Fabrică abstractă

Publicat în grup
Bună! Astăzi vom continua să studiem modelele de design și vom discuta despre modelul abstract din fabrică . Modele de design: Fabrică abstractă - 1Iată 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.
Pentru a înțelege pe deplin acest model, trebuie să fiți bine versat în următoarele subiecte:
  • 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
Aceste tipuri de unități sunt interconectate, deoarece servesc în aceeași armată. Am putea spune că categoriile enumerate mai sus sunt o familie de obiecte interconectate. Înțelegem asta. Dar modelul abstract de fabrică este folosit pentru a aranja crearea diferitelor familii de obiecte interconectate. Nici aici nu e nimic complicat. Să continuăm cu exemplul strategiei militare. În general, unitățile militare aparțin mai multor partide în conflict. În funcție de partea cui se află, unitățile militare pot varia semnificativ în aspect. Pedestrii, călăreții și arcașii armatei romane nu sunt la fel cu pedeștii, călăreții și arcașii vikingi. În strategia militară, soldații diferitelor armate sunt familii diferite de obiecte interconectate. Ar fi amuzant dacă un programator' Greșeala a făcut ca un soldat într-o uniformă franceză din epoca lui Napoleon, cu muscheta pregătită, să fie găsit mergând printre rândurile infanteriei romane. Modelul de design abstract al fabricii este necesar tocmai pentru rezolvarea acestei probleme. Nu, nu problema jenei care poate veni de la călătoria în timp, ci problema creării diferitelor grupuri de obiecte interconectate. O fabrică abstractă oferă o interfață pentru crearea tuturor produselor disponibile (o familie de obiecte). O fabrică abstractă are de obicei mai multe implementări. Fiecare dintre ei este responsabil pentru crearea produselor uneia dintre familii. Strategia noastră militară ar include o fabrică abstractă care creează soldați, arcași și cavaleri abstracti, precum și implementări ale acestei fabrici. De exemplu, o fabrică care creează legionari romani și o fabrică care creează soldați cartaginezi. Abstracția este cel mai important principiu călăuzitor al acestui tipar. Clienții fabricii lucrează cu fabrica și produsele acesteia doar prin interfețe abstracte. Drept urmare, nu trebuie să vă gândiți la ce soldați sunt creați în prezent. În schimb, treci această responsabilitate către o implementare concretă a fabricii abstracte.

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
Disclaimer: În fiecare interfață, am putea defini metode precum 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.
Rezultatul este că am implementat modelul abstract din fabrică.

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ă:
  1. Definiți familiile de produse. Să presupunem că avem două dintre ele:
    • SpecificProductA1,SpecificProductB1
    • SpecificProductA2,SpecificProductB2
  2. Pentru fiecare produs din familie, definiți o clasă abstractă (interfață). În cazul nostru avem:
    • ProductA
    • ProductB
  3. În cadrul fiecărei familii de produse, fiecare produs trebuie să implementeze interfața definită la pasul 2.
  4. 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();
  5. 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.
Următoarea diagramă UML ilustrează instrucțiunile prezentate mai sus: Modele de design: Fabrică abstractă - 3Acum vom scrie codul conform acestor instrucțiuni:
// 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:
  1. Rafinați aplicația de comandă de cafea, astfel încât să funcționeze și pe Linux.
  2. 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!
Comentarii
  • Popular
  • Nou
  • Vechi
Trebuie să fii conectat pentru a lăsa un comentariu
Această pagină nu are încă niciun comentariu