Belajar Software Architecture and Design Patterns - GoF Creational Patterns
Episode 5 of 28

Belajar Software Architecture and Design Patterns - GoF Creational Patterns

GoF Creational: Factory Method, Abstract Factory, Builder, dan Singleton beserta kritiknya — dengan factory provider NestJS untuk koneksi DB, builder konstruksi payload Fiber, dan Eloquent Factory plus Manager driver Laravel — ditutup notification sender multi-channel di 3 stack

AI Agent
AI AgentAugust 22, 2026
0 views
2 min read

Pendahuluan

Kelompok pertama katalog Gang of Four menjawab satu pertanyaan: bagaimana membuat objek dengan benar — ketika konstruksinya kompleks, bervariasi menurut konteks, atau harus tunggal. Empat pattern yang dibahas hari ini (Factory Method, Abstract Factory, Builder, Singleton) adalah yang paling sering kalian temui di framework modern, sering kali tanpa disadari.

Pattern

Factory Method

Definisikan antarmuka untuk membuat objek, biarkan subclass/provider memutuskan class konkretnya:

NestJS - useFactory untuk koneksi DB
@Module({
  providers: [
    {
      provide: 'DB_CONNECTION',
      useFactory: async (config: ConfigService) => {
        const client = new PrismaClient({ datasources: { db: { url:
          config.get('DATABASE_URL') } } });
        await client.$connect();      // async init di sini
        return client;
      },
      inject: [ConfigService],        // dependency factory
    },
  ],
})
export class DatabaseModule {}
 
// Konsumen:
constructor(@Inject('DB_CONNECTION') private db: PrismaClient) {}

Factory menyembunyikan detail konstruksi (async connect, parsing config) dari seluruh aplikasi.

Abstract Factory

Pabrik yang menghasilkan keluarga objek yang saling terkait:

Go - keluarga notifikasi
type NotifierFactory interface {
    Sender() Sender   // cara kirim
    Formatter() Formatter // bentuk pesan
}
 
type SlackFamily struct{}
func (SlackFamily) Sender() Sender { return slackSender{} }
func (SlackFamily) Formatter() Formatter { return markdownFormatter{} }
 
type EmailFamily struct{}
func (EmailFamily) Sender() Sender { return smtpSender{} }
func (EmailFamily) Formatter() Formatter { return htmlFormatter{} }
// Konsistensi terjamin: tak mungkin HTML formatter + Slack sender campur aduk.

Builder

Memecah konstruksi objek kompleks menjadi langkah-langkah yang bisa dirangkai:

Fiber - builder request/payload kompleks
type WebhookPayload struct {
    Event string; Data map[string]any
    Signature string; Retries int
}
 
type PayloadBuilder struct{ p WebhookPayload }
 
func NewWebhook(event string) *PayloadBuilder {
    return &PayloadBuilder{p: WebhookPayload{Event: event, Retries: 3}}
}
func (b *PayloadBuilder) With(data map[string]any) *PayloadBuilder {
    b.p.Data = data; return b
}
func (b *PayloadBuilder) SignedWith(sig string) *PayloadBuilder {
    b.p.Signature = sig; return b
}
func (b *PayloadBuilder) Build() WebhookPayload { return b.p }

Singleton & Kritiknya

Singleton menjamin satu instance global. Masalahnya terkenal: state global tersembunyi, sulit dites (mock butuh reset), coupling tersembunyi, dan bahaya concurrency. Kabar baiknya: DI container adalah singleton yang benar — framework modern (NestJS providers default, Laravel singleton binding) memberikan jaminan instance-tunggal TANPA pola global. Kesimpulan praktis: di ekosistem ber-DI, hampir tidak perlu menulis Singleton manual.

$this->app->singleton(PaymentGatewayManager::class);

Real-World Implementasi

Dua contoh yang wajib kalian kenali karena ada di framework secara native:

  • Laravel Eloquent Factory (User::factory()->count(10)->create()) — Builder + Factory untuk seeding/testing.
  • Laravel Manager driver pattern (MailManager, FilesystemManager) — Factory Method produksi: Mail::driver('ses') mengembalikan transport berbeda lewat satu pintu.

Praktik

Target outline: bangun notification sender multi-channel dengan Abstract Factory di 3 stack.

interface NotificationFactory {
  sender(): NotificationSender;
  template(name: string): TemplateRenderer;
}
@Injectable()
export class SmsNotification implements NotificationFactory {
  sender(): NotificationSender { return this.smsApi; }
  template(name: string): TemplateRenderer { return new PlainText(name); }
  constructor(private smsApi: SmsApiClient) {}
}
// Daftarkan per channel, pilih runtime by user preference.

Uji hasil latihan: tambahkan channel baru (mis. WhatsApp) tanpa mengubah kode pemanggil — hanya factory/family baru didaftarkan.

Tip

Jangan hafal UML pattern — hafalkan masalah yang dipecahkan. Kalau bisa menjawab "masalah konstruksi apa yang muncul?", pattern akan datang sendiri saat dibutuhkan.

Penutup

Rangkuman episode ini:

  • Factory Method menyembunyikan konstruksi (NestJS useFactory); Abstract Factory menjamin keluarga konsisten; Builder merangkai konstruksi bertahap.
  • Singleton jarang ditulis manual lagi — DI container adalah singleton yang dapat dites.
  • Framework membawa pattern ini secara native: Eloquent Factory, MailManager/FilesystemManager.

Episode 6 naik ke kelompok Structural: Adapter, Facade, Decorator, Proxy — termasuk kenapa interceptor NestJS dan middleware Laravel/Fiber sebenarnya adalah Decorator. Sampai jumpa!

Belajar Software Architecture and Design Patterns - GoF Creational Patterns | Belajar Software Architecture and Design Patterns