Menu
Coddy logo textTech

Factory ve Abstract Factory

Coddy'nin C++ Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası. Ders 92 / 104.

Factory kalıbı, nesne oluşturma işlemini ayrı bir yönteme veya sınıfa devreder ve tam sınıfını belirtmeden nesneler oluşturmanıza olanak tanır. Bu, oluşturma mantığı karmaşık olduğunda veya istemci kodunu somut uygulamalardan ayırmak istediğinizde kullanışlıdır.

Basit bir fabrika, girdiye göre farklı türetilmiş türler döndüren bir yöntem kullanır:

#include <iostream>
#include <memory>

class Button {
public:
    virtual void render() = 0;
    virtual ~Button() = default;
};

class WindowsButton : public Button {
public:
    void render() override { std::cout << "Windows button\n"; }
};

class MacButton : public Button {
public:
    void render() override { std::cout << "Mac button\n"; }
};

// Fabrika fonksiyonu
std::unique_ptr<Button> createButton(const std::string& os) {
    if (os == "windows") return std::make_unique<WindowsButton>();
    if (os == "mac") return std::make_unique<MacButton>();
    return nullptr;
}

Soyut Fabrika bunu bir adım ileri taşıyarak birbiriyle ilişkili nesne aileleri oluşturur. Tek bir fabrika yöntemi yerine, birden çok oluşturma yöntemine sahip bir fabrika arayüzünüz olur:

class Checkbox {
public:
    virtual void check() = 0;
    virtual ~Checkbox() = default;
};

class WindowsCheckbox : public Checkbox {
public:
    void check() override { std::cout << "Windows checkbox\n"; }
};

class MacCheckbox : public Checkbox {
public:
    void check() override { std::cout << "Mac checkbox\n"; }
};

// Soyut Fabrika
class GUIFactory {
public:
    virtual std::unique_ptr<Button> createButton() = 0;
    virtual std::unique_ptr<Checkbox> createCheckbox() = 0;
    virtual ~GUIFactory() = default;
};

class WindowsFactory : public GUIFactory {
public:
    std::unique_ptr<Button> createButton() override {
        return std::make_unique<WindowsButton>();
    }
    std::unique_ptr<Checkbox> createCheckbox() override {
        return std::make_unique<WindowsCheckbox>();
    }
};

Esnek nesne oluşturma gerektiğinde Factory’yi, ilişkili nesnelerin tutarlı bir şekilde birlikte çalışmasını sağlamanız gerektiğinde ise Abstract Factory’yi kullanın.

challenge icon

Görev

Kolay

Factory ve Abstract Factory kalıplarını kullanarak bir Belge Oluşturucu sistemi oluşturalım. Farklı çıktı biçimleri (PDF ve HTML) için farklı belge türleri (raporlar ve faturalar) oluşturabilen bir sistem geliştirecek ve factory'lerin nesne oluşturmayı istemci kodundan nasıl ayırdığını göstereceksin.

Kodunu dört dosya arasında düzenleyeceksin:

  • Document.h: Belge ürün hiyerarşisini tanımla.

    Üretilen belgeyi açıklayan bir dize döndüren saf sanal Document metoduna ve sanal bir yıkıcıya sahip soyut bir temel generate() sınıfı oluştur.

    Ardından dört somut belge sınıfı oluştur:

    • PDFReport: generate(), "Generating PDF Report" döndürür
    • HTMLReport: generate(), "Generating HTML Report" döndürür
    • PDFInvoice: generate(), "Generating PDF Invoice" döndürür
    • HTMLInvoice: generate(), "Generating HTML Invoice" döndürür
  • DocumentFactory.h: Hem basit bir factory fonksiyonu hem de abstract factory uygula.

    İlk olarak, iki dize alan createDocument adlı basit bir factory fonksiyonu oluştur: bir belge türü ("report" veya "invoice") ve bir biçim ("pdf" veya "html"). Uygun somut belgeyi gösteren bir std::unique_ptr<Document> döndürmelidir. Geçersiz birleşimler için nullptr döndür.

    Ardından iki saf sanal metoda sahip DocumentFactory adlı bir abstract factory sınıfı oluştur:

    • createReport(): bir std::unique_ptr<Document> döndürür
    • createInvoice(): bir std::unique_ptr<Document> döndürür

    İki somut factory uygula:

    • PDFFactory: PDFReport ve PDFInvoice oluşturur
    • HTMLFactory: HTMLReport ve HTMLInvoice oluşturur
  • DocumentService.h: Abstract factory kullanan bir servis oluştur.

    Yapıcısında DocumentService alan bir std::unique_ptr<DocumentFactory> sınıfı tanımla. Bu sınıf, factory'yi kullanarak hem bir rapor hem de bir fatura oluşturan, ardından her biri üzerinde generateAllDocuments() çağrısının sonucunu satır başına bir tane olacak şekilde yazdıran generate() adlı bir metoda sahip olmalıdır.

  • main.cpp: Her iki factory yaklaşımını göster.

    İki girdi oku:

    1. Bir belge türü (report veya invoice)
    2. Bir biçim (pdf veya html)

    İlk olarak, girdilere göre bir belge oluşturmak için basit factory fonksiyonunu kullan. Üzerinde generate() çağrısının sonucunu yazdır.

    Ardından boş bir satır yazdır.

    Sonra biçim girdisine göre uygun factory ile bir DocumentService oluştur (PDFFactory için pdf, HTMLFactory için html kullan). Abstract factory'nin birbiriyle ilişkili belge ailesi oluşturma biçimini göstermek için generateAllDocuments() çağrısını yap.

Örneğin, girdiler report ve pdf olduğunda:

Generating PDF Report

Generating PDF Report
Generating PDF Invoice

Girdiler invoice ve html olduğunda:

Generating HTML Invoice

Generating HTML Report
Generating HTML Invoice

Basit factory'nin her iki parametreye göre tek bir belge oluşturduğuna, abstract factory'nin ise bir servis tarafından oluşturulan tüm belgelerin aynı biçimi paylaşmasını sağladığına dikkat et. Bu, birlikte tutarlı biçimde çalışması gereken birbiriyle ilişkili nesne ailelerine ihtiyaç duyduğunda Abstract Factory'nin temel avantajıdır.

Kendin dene

#include <iostream>
#include <string>
#include <memory>
#include "Document.h"
#include "DocumentFactory.h"
#include "DocumentService.h"

using namespace std;

int main() {
    // Girdileri oku
    string documentType;
    string format;
    cin >> documentType;
    cin >> format;
    
    // TODO: Bir belge oluşturmak için basit fabrika fonksiyonunu kullan
    // documentType ve format girdilerine göre
    // Üzerinde generate() çağrısının sonucunu yazdır
    
    // Boş bir satır yazdır
    cout << endl;
    
    // TODO: Uygun fabrika ile bir DocumentService oluştur
    // format girdisine göre ("pdf" için PDFFactory, "html" için HTMLFactory)
    // Soyut fabrikayı göstermek için generateAllDocuments() çağır
    
    return 0;
}
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Nesne Yönelimli Programlama bölümündeki tüm dersler

Kendi başına pratik yap: Online C++ derleyicisi