Factory – wzorzec projektowy

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.

Tagi: Brak tagów

Add a Comment

Your email address will not be published. Required fields are marked *