」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > 單例設計模式

單例設計模式

發佈於2024-07-30
瀏覽:635

Singleton Design Pattern

單例設計模式是軟體程式設計中最重要且最常用的設計模式之一。它確保類別在應用程式運行時只有一個實例,並提供對該實例的全域存取點。在這篇文章中,我們將討論 Singleton 的重要性,如何在 Golang 中實現它,以及它帶來的好處,特別是在並發環境中。

什麼是單例?

Singleton 是一種將類別的實例限制為單一實例的設計模式。它在需要單點控製或單一共享資源的情況下特別有用,例如:

  • 設定管理器,需要集中應用程式設定。
  • 資料庫連線池,必須有效管理有限數量的連線。
  • 記錄器,其中日誌一致性至關重要。

為什麼要使用單例?

我將列出一些關於 Pattern 實現的更有意義的觀點,同時也表明並非一切都是美好的,我們可能會遇到一些問題。

好處

  • 全域一致性:確保應用程式的所有點都使用相同的實例,提供資料和行為的一致性。
  • 存取控制:集中控制實例的建立和訪問,方便物件生命週期的維護和管理。
  • 資源效率:避免不必要的多個實例創建,節省記憶體和處理資源。

缺點

  • 測試難度:單例會使編寫單元測試變得更加困難,因為它們引入了需要管理的全局狀態。
  • 增加耦合:過度使用單例會導致元件之間的耦合更緊密,從而難以維護和發展應用程式。

實作單例

為了實作單例,我將使用 Golang。在這種語言中,我們必須特別注意並發性,以確保只創建一個實例,即使多個 goroutine 嘗試同時存取該實例也是如此。

為了讓我們的範例更接近現實世界,讓我們為我們的應用程式建立一個記錄器。記錄器是應用程式中常用的工具,需要唯一以確保日誌一致性。

1 - 定義結構

首先,我們定義我們想要擁有單一實例的結構。

package logger

import (
    "fmt"
    "sync"
)

type Logger struct {}

var loggerInstance *Logger

2 - 實作NewInstance函數

NewInstance函數負責傳回Singleton結構的單一實例。我們使用互斥體來確保並發環境中的安全性,實現雙重檢查鎖定以提高效率。

package logger

import (
    "fmt"
    "sync"
)

type Logger struct{}

var logger *Logger
var mtx = &sync.Mutex{}

func NewInstance() *Logger {
    if logger == nil {
        mtx.Lock()
        defer mtx.Unlock()
        if logger == nil {
            fmt.Println("Creating new Logger")
            logger = &Logger{}
        }
    } else {
        fmt.Println("Logger already created")
    }
    return logger
}

3 - 實作日誌類型

日誌工具總是有一些日誌類型,例如Info僅顯示訊息,Error顯示錯誤等等。這也是過濾我們想要在應用程式中顯示的資訊類型的一種方法。

因此,讓我們建立一個方法來顯示 Info 類型的日誌。為此,我們將建立一個函數來接收日誌訊息並將其格式化為 INFO 格式。

package logger

import (
    "fmt"
    "sync"
    "time"
)

const (
    INFO    string = "INFO"
)

type Logger struct{}

var logger *Logger
var mtx = &sync.Mutex{}

func NewInstance() *Logger {
    if logger == nil {
        mtx.Lock()
        defer mtx.Unlock()
        if logger == nil {
            fmt.Println("Creating new logger")
            logger = &Logger{}
        }
    } else {
        fmt.Println("Logger already created")
    }
    return logger
}

func (l *Logger) Info(message string) {
    fmt.Printf("%s - %s: %s\n", time.Now().UTC().Format(time.RFC3339Nano), INFO, message)
}

4 - 使用記錄器

要使用我們的新記錄器,我們將在主套件中實例化它並建立日誌以查看此實作的工作原理。

package main

import (
    "playground-go/pkg/logger"
)

func main() {
    log := logger.NewInstance()
    log.Info("This is an example of log")
}

這是我們運行程式的結果:

Creating new logger
2024-07-03T19:34:57.609599Z - INFO: This is an example of log

如果我們想測試NewInstance是否真的保證只有一個實例在運行,我們可以進行以下測試。

package main

import (
    "fmt"
    "playground-go/pkg/logger"
)

func main() {
    log := logger.NewInstance()
    log.Info("This is an example of log")

    log2 := logger.NewInstance()
    log2.Info("This is another example of log")

    if log == log2 {
        fmt.Println("same instance")
    } else {
        fmt.Println("different instance")
    }
}

我們的日誌已更改,現在我們可以看到我們阻止了新實例的建立:

Creating new logger
2024-07-03T19:45:19.603783Z - INFO: This is an example of log
Logger already created
2024-07-03T19:45:19.603793Z - INFO: This is another example of log
same instance

結論

單例模式是一種強大的工具,可確保應用程式運行時僅存在特定類別的一個實例。在記錄器範例中,我們了解如何應用此模式來確保整個應用程式中的日誌一致性。

希望這可以幫助您更好地理解 Golang 中的 Singleton。

版本聲明 本文轉載於:https://dev.to/rflpazini/singleton-design-pattern-1n51?1如有侵犯,請洽[email protected]刪除
最新教學 更多>

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3