Przeznaczenie
Głównym założeniem fabryki, tak jak w rzeczywistym świecie, jest wytwarzanie obiektów. Dzięki wykorzystaniu fabryki można ukryć szczegóły implementacyjne tworzenia obiektów i odseparować je od logiki biznesowej.
Dlaczego go potrzebujemy ?
- mamy wiele klas, które dziedziczą po tej samej klasie bazowej lub implementują ten sam interfejs
- chcemy uniknąć bezpośredniego tworzenia obiektów przez kod klienta
- chcemy odizolować logikę tworzenia obiektów od reszty kodu
- chcemy ułatwić testowanie
Poniżej przykładowy kod przed użyciem wzorca Factory:
public abstract class Document {
private String title;
private String author;
private String content;
public Document(String title, String author, String content) {
this.title = title;
this.author = author;
this.content = content;
}
public String getTitle() {
return title;
}
public String getContent() {
return content;
}
public String getAuthor() {
return author;
}
}
public class WordDocument extends Document{
public WordDocument(String title, String author, String content) {
super(title, author, content);
}
}
public class PdfDocument extends Document{
public PdfDocument(String title, String author, String content) {
super(title, author, content);
}
}
public class Main {
public static void main(String[] args) {
Document textDocument = new WordDocument("Wzorce projektowe", "Sebastian", "Zawartość dokumentu Word");
Document pdfDocument = new PdfDocument("Wzorce projektowe", "Sebastian", "Zawartość dokumentu PDF");
}
}
Metoda fabrykująca (Factory Method) – schemat działania
Struktura:

Kod:
public abstract class Document {
private String title;
private String author;
private DocumentType type;
private String content;
public Document(String title, String author, DocumentType type, String content) {
this.title = title;
this.author = author;
this.type = type;
this.content = content;
}
public String getTitle() {
return title;
}
public String getContent() {
return content;
}
public String getAuthor() {
return author;
}
public DocumentType getType() {
return type;
}
@Override
public String toString() {
return "Document{" +
"title='" + title + '\'' +
", author='" + author + '\'' +
", type=" + type +
", content='" + content + '\'' +
'}';
}
}
public class PdfDocument extends Document{
public PdfDocument(String title, String author, DocumentType type, String content) {
super(title, author, type, content);
}
}
public class WordDocument extends Document{
public WordDocument(String title, String author,DocumentType type, String content) {
super(title, author, type, content);
}
}
public enum DocumentType {
WORD, PDF
}
abstract public class Factory {
abstract public Document createDocument(DocumentType type);
}
public class DocumentFactory extends Factory {
@Override
public Document createDocument(DocumentType documentType) {
switch (documentType) {
case WORD:
return new WordDocument("Wzorce projektowe","Sebastian", documentType,"Zawartość dokumentu Word");
case PDF:
return new PdfDocument("Wzorce projektowe","Sebastian",documentType,"Zawartość dokumentu PDF");
default:
throw new UnsupportedOperationException("No such type");
}
}
}
public class Main {
public static void main(String[] args) {
Factory factory = new DocumentFactory();
Document wordDocument = factory.createDocument(DocumentType.WORD);
Document pdfDocument = factory.createDocument(DocumentType.PDF);
System.out.println(wordDocument);
System.out.println(pdfDocument);
}
}
Fabryka abstrakcyjna (Abstract Factory) – schemat działania
Struktura:

Kod:
public abstract class Document {
private String title;
private String author;
private DocumentType type;
private String content;
public Document(String title, String author, DocumentType type, String content) {
this.title = title;
this.author = author;
this.type = type;
this.content = content;
}
public String getTitle() {
return title;
}
public String getContent() {
return content;
}
public String getAuthor() {
return author;
}
public DocumentType getType() {
return type;
}
@Override
public String toString() {
return "Document{" +
"title='" + title + '\'' +
", author='" + author + '\'' +
", type=" + type +
", content='" + content + '\'' +
'}';
}
}
public class PdfDocument extends Document {
public PdfDocument(String title, String author, DocumentType type, String content) {
super(title, author, type, content);
}
}
public class WordDocument extends Document {
public WordDocument(String title, String author, DocumentType type, String content) {
super(title, author, type, content);
}
}
public enum DocumentType {
WORD, PDF
}
abstract public class Factory {
abstract public WordDocument createWordDocument();
abstract public PdfDocument createPdfDocument();
}
public class RedFactory extends Factory {
@Override
public WordDocument createWordDocument() {
return new WordDocument("Word Czerwony", "Sebastian", DocumentType.WORD, "Zawartość dokumentu Word");
}
@Override
public PdfDocument createPdfDocument() {
return new PdfDocument("Pdf Czerwony", "Sebastian", DocumentType.PDF, "Zawartość dokumentu PDF");
}
}
public class BlueFactory extends Factory {
@Override
public WordDocument createWordDocument() {
return new WordDocument("Word Niebieski", "Sebastian", DocumentType.WORD, "Zawartość dokumentu Word");
}
@Override
public PdfDocument createPdfDocument() {
return new PdfDocument("Pdf Niebieski", "Sebastian", DocumentType.PDF, "Zawartość dokumentu PDF");
}
}
public class Main {
public static void main(String[] args) {
Factory blueFactory = new BlueFactory();
Factory redFactory = new RedFactory();
WordDocument blueWord = blueFactory.createWordDocument();
PdfDocument bluePdf = blueFactory.createPdfDocument();
WordDocument redWord = redFactory.createWordDocument();
PdfDocument redPdf = redFactory.createPdfDocument();
System.out.println(blueWord);
System.out.println(bluePdf);
System.out.println(redWord);
System.out.println(redPdf);
}
}
Podsumowanie
Wzorzec Factory (oraz jego rozszerzenie – Abstract Factory) pozwala oddzielić logikę tworzenia obiektów od logiki aplikacji, dzięki czemu kod staje się bardziej przejrzysty, łatwiejszy w testowaniu i utrzymaniu.
Dzięki zastosowaniu fabryk:
- Ukrywamy szczegóły implementacyjne tworzenia obiektów
- Unikamy powtarzania kodu konstrukcyjnego
- Możemy dynamicznie decydować, jaką klasę stworzyć
- Łatwiej modyfikować i rozwijać aplikację bez naruszania istniejącej logiki
Wersja Factory Method dobrze sprawdza się, gdy mamy jedną rodzinę klas, a Abstract Factory – gdy potrzebujemy tworzyć różne zestawy współpracujących obiektów.
To podejście pozwala pisać czystszy, skalowalny i bardziej elastyczny kod, zgodny z zasadami SOLID.
