Factory Method Pattern #

Dalam pengembangan perangkat lunak modern, salah satu tantangan terbesar adalah bagaimana membuat sistem yang fleksibel, mudah diperluas, dan terpisah dari detail implementasi. Salah satu solusi yang sering digunakan adalah Factory Method Pattern. Pattern ini memungkinkan developer untuk memisahkan proses pembuatan objek dari penggunaan objek itu sendiri, sehingga sistem menjadi lebih modular dan mudah beradaptasi dengan perubahan di masa depan.

Artikel ini akan membahas secara mendetail mengenai Factory Method Pattern: apa itu, tujuan penggunaannya, kapan cocok diterapkan, contoh implementasi menggunakan Golang, serta best practice yang sebaiknya diikuti. Dengan memahami pattern ini, kamu dapat menulis kode yang lebih bersih, extensible, dan maintainable.

Apa itu Factory Method Pattern? #

Factory Method Pattern adalah salah satu creational design pattern yang bertujuan untuk mendefinisikan interface atau abstract method untuk membuat sebuah objek, tetapi membiarkan subclass atau implementasi konkret yang menentukan kelas apa yang akan di-instansiasi.

Intinya:

  • Kode client tidak bergantung langsung pada concrete class
  • Proses pembuatan objek dienkapsulasi dalam sebuah factory method
  • Sistem menjadi lebih fleksibel, extensible, dan testable

Pattern ini sangat umum digunakan di framework, library, dan sistem berskala besar di mana jenis objek bisa bertambah di masa depan.

Tujuan Pattern #

Factory Method dibuat untuk menyelesaikan beberapa masalah klasik:

  1. Menghindari coupling langsung ke concrete class Client hanya tahu interface, bukan implementasinya.

  2. Mendukung Open–Closed Principle (OCP) Menambah tipe baru tanpa mengubah kode client.

  3. Memusatkan logic pembuatan objek Creation logic tidak tersebar di banyak tempat.

  4. Mempermudah testing dan mocking Object creation bisa diganti dengan fake atau mock.


Kapan Cocok Digunakan? #

Gunakan Factory Method jika:

  • Kamu belum tahu pasti tipe objek apa yang akan dibuat saat compile-time
  • Sistem perlu mudah diperluas dengan tipe baru
  • Banyak if / switch berdasarkan tipe objek
  • Object creation memiliki logic kompleks
  • Kamu ingin memisahkan what to create dan how to use

Jangan Gunakan Jika? #

  • Hanya ada satu implementasi dan tidak akan bertambah
  • Object creation sangat sederhana dan stabil

Struktur Pattern #

Secara konsep terdiri dari:

  • Product → interface / abstract type
  • ConcreteProduct → implementasi dari Product
  • Creator / Factory → mendefinisikan factory method
  • ConcreteCreator → mengembalikan ConcreteProduct tertentu

Contoh Implementasi (Golang) #

Contoh Kasus: Payment System #

Kita ingin mendukung beberapa metode pembayaran: CreditCard dan EWallet.

Product Interface #

type Payment interface {
    Pay(amount int) error
}

Concrete Products #

type CreditCardPayment struct{}

func (c *CreditCardPayment) Pay(amount int) error {
    fmt.Println("Paying", amount, "using Credit Card")
    return nil
}
type EWalletPayment struct{}

func (e *EWalletPayment) Pay(amount int) error {
    fmt.Println("Paying", amount, "using E-Wallet")
    return nil
}

Factory Method #

type PaymentFactory interface {
    CreatePayment() Payment
}

Concrete Factories #

type CreditCardFactory struct{}

func (f *CreditCardFactory) CreatePayment() Payment {
    return &CreditCardPayment{}
}
type EWalletFactory struct{}

func (f *EWalletFactory) CreatePayment() Payment {
    return &EWalletPayment{}
}

Client Code #

func ProcessPayment(factory PaymentFactory, amount int) error {
    payment := factory.CreatePayment()
    return payment.Pay(amount)
}
func main() {
    ccFactory := &CreditCardFactory{}
    ewalletFactory := &EWalletFactory{}

    ProcessPayment(ccFactory, 100000)
    ProcessPayment(ewalletFactory, 50000)
}

Client tidak tahu apakah yang dipakai CreditCard atau EWallet.


Factory Method vs Simple Factory #

Di Go, sering kali Factory Method disederhanakan menjadi fungsi:

func NewPayment(method string) (Payment, error) {
    switch method {
    case "credit_card":
        return &CreditCardPayment{}, nil
    case "ewallet":
        return &EWalletPayment{}, nil
    default:
        return nil, errors.New("unknown payment method")
    }
}

Kapan pakai versi ini? #

  • Sistem kecil
  • Tipe tidak sering berubah

Kapan pakai Factory Method penuh? #

  • Sistem modular
  • Plugin-based architecture
  • Banyak variasi dan logic kompleks

Kelebihan dan Kekurangan #

Kelebihan #

  • Loose coupling
  • Mudah extensible
  • Lebih testable
  • Lebih rapi untuk sistem besar

Kekurangan #

  • Banyak struct dan file
  • Overkill untuk sistem sederhana

Factory Method di Dunia Nyata #

Beberapa contoh nyata:

  • database/sqlsql.Open() memilih driver
  • Logging library → memilih output (file, stdout, remote)
  • HTTP client → memilih transport atau strategy
  • Message queue → memilih Kafka, SQS, Pub/Sub

Best Practices #

  1. Return interface, bukan concrete type

  2. Jangan taruh business logic di factory Factory hanya fokus pada creation.

  3. Nama factory harus eksplisit Contoh: PaymentFactory, LoggerFactory

  4. Hindari switch yang terlalu besar Jika switch mulai membesar, itu sinyal perlu refactor ke Factory Method.

  5. Gabungkan dengan Dependency Injection Factory sangat cocok digunakan bersama DI.

  6. Gunakan error handling yang jelas Factory boleh gagal jika input tidak valid.


Penutup #

Factory Method Pattern adalah solusi elegan untuk memisahkan object creation dari object usage. Pattern ini sangat relevan untuk sistem yang:

  • Berkembang cepat
  • Memiliki banyak variasi implementasi
  • Mengutamakan clean architecture

Jika kamu mulai melihat banyak if atau switch berbasis tipe, itu sering kali tanda bahwa Factory Method layak dipertimbangkan.

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact