![Fabryka abstrakcyjna](/images/patterns/cards/abstract-factory-mini.png?id=4c3927c446313a38ce77dfee38111e27)
Fabryka abstrakcyjna w języku Java
Fabryka abstrakcyjna jest kreacyjnym wzorcem projektowym, który pozwala tworzyć rodziny spokrewnionych ze sobą obiektów bez określania ich konkretnych klas.
Fabryka abstrakcyjna definiuje interfejs służący tworzeniu poszczególnych produktów, ale pozostawia faktyczne tworzenie produktów konkretnym klasom fabrycznym. Każdy typ fabryki odpowiada jednemu z wariantów produktu.
Kod klienta wywołuje metody kreacyjne obiektu fabrycznego zamiast tworzyć produkty bezpośrednio — wywołując konstruktor (za pomocą operatora new
). Skoro dana fabryka odpowiada jednemu z wariantów produktu, to wszystkie jej produkty będą ze sobą kompatybilne.
Kod klienta współpracuje z fabrykami i produktami wyłącznie poprzez ich abstrakcyjne interfejsy. Dzięki temu jeden klient jest kompatybilny z wieloma różnymi produktami. Wystarczy stworzyć nową konkretną klasę fabryczną i przekazać ją kodowi klienta.
Jeśli masz problem ze zrozumieniem różnicy pomiędzy poszczególnymi koncepcjami i wzorcami wytwórczymi, przeczytaj nasze Porównanie fabryk.
Złożoność:
Popularność:
Przykłady użycia: Wzorzec Fabryka abstrakcyjna jest dość powszechnie stosowany w kodzie Java. Wiele frameworków i bibliotek dzięki niemu pozwala rozszerzać i dostosowywać swoje standardowe komponenty.
Oto przykłady użycia wzorca w głównych bibliotekach Java:
Identyfikacja: Wzorzec łatwo można rozpoznać na podstawie metod które zwracają obiekty fabryczne, służące następnie tworzeniu konkretnych pod-komponentów.
Rodziny międzyplatformowych komponentów graficznego interfejsu użytkownika (GUI) i ich wytwarzanie
W tym przykładzie przyciski i pola wyboru posłużą za produkty. Mamy dwa warianty: kontrolki w stylu macOS oraz Windows.
Fabryka abstrakcyjna definiuje interfejs mający służyć tworzeniu przycisków oraz pól wyboru. Są dwie konkretne fabryki, z których każda zwraca produkty w jednym z wariantów.
Kod klienta współpracuje z fabrykami i produktami za pośrednictwem abstrakcyjnych interfejsów. Pozwala to jednemu klientowi współdziałać z wieloma wariantami produktu — zależnie od typu obiektu fabrycznego.
buttons: Pierwsza hierarchia produktów
buttons/Button.java
package refactoring_guru.abstract_factory.example.buttons;
/**
* Abstract Factory assumes that you have several families of products,
* structured into separate class hierarchies (Button/Checkbox). All products of
* the same family have the common interface.
*
* This is the common interface for buttons family.
*/
public interface Button {
void paint();
}
buttons/MacOSButton.java
package refactoring_guru.abstract_factory.example.buttons;
/**
* All products families have the same varieties (MacOS/Windows).
*
* This is a MacOS variant of a button.
*/
public class MacOSButton implements Button {
@Override
public void paint() {
System.out.println("You have created MacOSButton.");
}
}
buttons/WindowsButton.java
package refactoring_guru.abstract_factory.example.buttons;
/**
* All products families have the same varieties (MacOS/Windows).
*
* This is another variant of a button.
*/
public class WindowsButton implements Button {
@Override
public void paint() {
System.out.println("You have created WindowsButton.");
}
}
checkboxes: Druga hierarchia produktów
checkboxes/Checkbox.java
package refactoring_guru.abstract_factory.example.checkboxes;
/**
* Checkboxes is the second product family. It has the same variants as buttons.
*/
public interface Checkbox {
void paint();
}
checkboxes/MacOSCheckbox.java
package refactoring_guru.abstract_factory.example.checkboxes;
/**
* All products families have the same varieties (MacOS/Windows).
*
* This is a variant of a checkbox.
*/
public class MacOSCheckbox implements Checkbox {
@Override
public void paint() {
System.out.println("You have created MacOSCheckbox.");
}
}
checkboxes/WindowsCheckbox.java
package refactoring_guru.abstract_factory.example.checkboxes;
/**
* All products families have the same varieties (MacOS/Windows).
*
* This is another variant of a checkbox.
*/
public class WindowsCheckbox implements Checkbox {
@Override
public void paint() {
System.out.println("You have created WindowsCheckbox.");
}
}
factories
factories/GUIFactory.java: Fabryka abstrakcyjna
package refactoring_guru.abstract_factory.example.factories;
import refactoring_guru.abstract_factory.example.buttons.Button;
import refactoring_guru.abstract_factory.example.checkboxes.Checkbox;
/**
* Abstract factory knows about all (abstract) product types.
*/
public interface GUIFactory {
Button createButton();
Checkbox createCheckbox();
}
factories/MacOSFactory.java: Konkretna fabryka (macOS)
package refactoring_guru.abstract_factory.example.factories;
import refactoring_guru.abstract_factory.example.buttons.Button;
import refactoring_guru.abstract_factory.example.buttons.MacOSButton;
import refactoring_guru.abstract_factory.example.checkboxes.Checkbox;
import refactoring_guru.abstract_factory.example.checkboxes.MacOSCheckbox;
/**
* Each concrete factory extends basic factory and responsible for creating
* products of a single variety.
*/
public class MacOSFactory implements GUIFactory {
@Override
public Button createButton() {
return new MacOSButton();
}
@Override
public Checkbox createCheckbox() {
return new MacOSCheckbox();
}
}
factories/WindowsFactory.java: Konkretna fabryka (Windows)
package refactoring_guru.abstract_factory.example.factories;
import refactoring_guru.abstract_factory.example.buttons.Button;
import refactoring_guru.abstract_factory.example.buttons.WindowsButton;
import refactoring_guru.abstract_factory.example.checkboxes.Checkbox;
import refactoring_guru.abstract_factory.example.checkboxes.WindowsCheckbox;
/**
* Each concrete factory extends basic factory and responsible for creating
* products of a single variety.
*/
public class WindowsFactory implements GUIFactory {
@Override
public Button createButton() {
return new WindowsButton();
}
@Override
public Checkbox createCheckbox() {
return new WindowsCheckbox();
}
}
app
app/Application.java: Kod klienta
package refactoring_guru.abstract_factory.example.app;
import refactoring_guru.abstract_factory.example.buttons.Button;
import refactoring_guru.abstract_factory.example.checkboxes.Checkbox;
import refactoring_guru.abstract_factory.example.factories.GUIFactory;
/**
* Factory users don't care which concrete factory they use since they work with
* factories and products through abstract interfaces.
*/
public class Application {
private Button button;
private Checkbox checkbox;
public Application(GUIFactory factory) {
button = factory.createButton();
checkbox = factory.createCheckbox();
}
public void paint() {
button.paint();
checkbox.paint();
}
}
Demo.java: Konfiguracja aplikacji
package refactoring_guru.abstract_factory.example;
import refactoring_guru.abstract_factory.example.app.Application;
import refactoring_guru.abstract_factory.example.factories.GUIFactory;
import refactoring_guru.abstract_factory.example.factories.MacOSFactory;
import refactoring_guru.abstract_factory.example.factories.WindowsFactory;
/**
* Demo class. Everything comes together here.
*/
public class Demo {
/**
* Application picks the factory type and creates it in run time (usually at
* initialization stage), depending on the configuration or environment
* variables.
*/
private static Application configureApplication() {
Application app;
GUIFactory factory;
String osName = System.getProperty("os.name").toLowerCase();
if (osName.contains("mac")) {
factory = new MacOSFactory();
} else {
factory = new WindowsFactory();
}
app = new Application(factory);
return app;
}
public static void main(String[] args) {
Application app = configureApplication();
app.paint();
}
}
OutputDemo.txt: Wyniki działania
You create WindowsButton.
You created WindowsCheckbox.