Menu
CoddyTech

Pola Singleton

Termasuk bagian Pemrograman Berorientasi Objek dalam perjalanan GO di Coddy. Pelajaran 86 dari 107.

Pola Singleton memastikan bahwa suatu tipe hanya memiliki satu instance di seluruh programmu dan menyediakan titik akses global ke instance tersebut. Pola ini berguna untuk sumber daya bersama seperti pengelola konfigurasi, koneksi database, atau pencatat log.

Di Go, kita menerapkan Singleton menggunakan variabel tingkat package yang dipadukan dengan sync.Once untuk menjamin inisialisasi yang aman untuk thread:

package config

import "sync"

type Config struct {
    DatabaseURL string
    MaxRetries  int
}

var (
    instance *Config
    once     sync.Once
)

func GetInstance() *Config {
    once.Do(func() {
        instance = &Config{
            DatabaseURL: "localhost:5432",
            MaxRetries:  3,
        }
    })
    return instance
}

sync.Once menjamin bahwa fungsi inisialisasi dijalankan tepat satu kali, bahkan ketika beberapa goroutine memanggil GetInstance() secara bersamaan. Setiap pemanggilan berikutnya mengembalikan instance yang sama tanpa menjalankan ulang kode inisialisasi.

cfg1 := config.GetInstance()
cfg2 := config.GetInstance()
// cfg1 dan cfg2 merujuk ke instance yang sama

Gunakan Singleton secukupnya. Meskipun praktis, Singleton memperkenalkan state global yang dapat mempersulit pengujian dan menyembunyikan dependensi. Pertimbangkan apakah dependency injection bisa menjadi alternatif yang lebih baik untuk kasus penggunaanmu.

challenge icon

Tantangan

Mudah

Mari buat singleton Logger yang memastikan hanya ada satu instance logger di seluruh aplikasi kamu! Ini adalah kasus penggunaan klasik untuk pola Singleton. Kamu ingin semua bagian programmu menggunakan konfigurasi dan status logger yang sama.

Kamu akan membagi kodemu ke dalam dua file:

  • logger.go: Implementasikan logger Singleton yang aman untuk thread.

    Buat struct Logger dengan dua field: Prefix (string) untuk awalan pesan log, dan MessageCount (int) untuk melacak jumlah pesan yang sudah dicatat.

    Gunakan variabel tingkat package dengan sync.Once untuk memastikan hanya satu instance yang dibuat. Implementasikan fungsi GetLogger() yang menginisialisasi logger dengan awalan default "[LOG]" dan mengembalikan instance singleton.

    Tambahkan method berikut ke Logger:

    • SetPrefix(prefix string) - mengubah awalan logger
    • Log(message string) string - menambah jumlah pesan dan mengembalikan string berformat: [prefix] #[count]: [message]
    • GetCount() int - mengembalikan jumlah total pesan yang sudah dicatat
  • main.go: Tunjukkan bahwa beberapa pemanggilan GetLogger() mengembalikan instance yang sama.

    Baca nilai awalan baru, lalu baca jumlah pesan, diikuti dengan setiap pesan yang akan dicatat.

    Dapatkan instance logger, tetapkan awalan khusus, lalu catat setiap pesan dan cetak hasilnya. Setelah mencatat semua pesan, dapatkan instance logger lagi (untuk membuktikan bahwa itu instance yang sama) dan cetak jumlah total pesan.

Input berikut akan diberikan:

  • Baris 1: Awalan khusus yang akan ditetapkan
  • Baris 2: Jumlah pesan
  • Baris berikutnya: Setiap pesan yang akan dicatat

Contohnya, jika inputnya:

[APP]
3
Server started
User connected
Request processed

Output kamu seharusnya:

[APP] #1: Server started
[APP] #2: User connected
[APP] #3: Request processed
Total messages logged: 3

Dan jika inputnya:

[DEBUG]
2
Initializing cache
Cache ready

Output kamu seharusnya:

[DEBUG] #1: Initializing cache
[DEBUG] #2: Cache ready
Total messages logged: 2

Dan jika inputnya:

[ERROR]
1
Connection failed

Output kamu seharusnya:

[ERROR] #1: Connection failed
Total messages logged: 1

Inti pentingnya adalah, berapa kali pun kamu memanggil GetLogger(), kamu selalu mendapatkan instance yang sama dengan status bersama. Jumlah pesan tetap tersimpan karena hanya ada satu Logger!

Coba sendiri

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	// Baca prefiks khusus
	prefix, _ := reader.ReadString('\n')
	prefix = strings.TrimSpace(prefix)

	// Baca jumlah pesan
	countStr, _ := reader.ReadString('\n')
	countStr = strings.TrimSpace(countStr)
	count, _ := strconv.Atoi(countStr)

	// Baca setiap pesan
	messages := make([]string, count)
	for i := 0; i < count; i++ {
		msg, _ := reader.ReadString('\n')
		messages[i] = strings.TrimSpace(msg)
	}

	// TODO: Dapatkan instance logger menggunakan GetLogger()

	// TODO: Atur prefiks khusus menggunakan SetPrefix()

	// TODO: Catat setiap pesan dan cetak hasilnya

	// TODO: Dapatkan kembali instance logger (untuk membuktikan bahwa instance-nya sama)
	// dan cetak jumlah total pesan dengan format: "Total messages logged: X"
}
quiz iconUji dirimu

Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.

Semua pelajaran di Pemrograman Berorientasi Objek

Latihan sendiri: Compiler Go online