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

單例設計模式

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

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]刪除
最新教學 更多>
  • 為什麼儘管有效代碼,為什麼在PHP中捕獲輸入?
    為什麼儘管有效代碼,為什麼在PHP中捕獲輸入?
    在php ;?>" method="post">The intention is to capture the input from the text box and display it when the submit button is clicked.但是,輸出...
    程式設計 發佈於2025-03-10
  • 如何在JavaScript對像中動態設置鍵?
    如何在JavaScript對像中動態設置鍵?
    在嘗試為JavaScript對象創建動態鍵時,如何使用此Syntax jsObj['key' i] = 'example' 1;不工作。正確的方法採用方括號: jsobj ['key''i] ='example'1; 在JavaScript中,數組是一...
    程式設計 發佈於2025-03-10
  • 如何使用組在MySQL中旋轉數據?
    如何使用組在MySQL中旋轉數據?
    在關係數據庫中使用mySQL組使用mySQL組進行查詢結果,在關係數據庫中使用MySQL組,轉移數據的數據是指重新排列的行和列的重排以增強數據可視化。在這裡,我們面對一個共同的挑戰:使用組的組將數據從基於行的基於列的轉換為基於列。讓我們考慮以下查詢: select data d.data_ti...
    程式設計 發佈於2025-03-10
  • 如何使用替換指令在GO MOD中解析模塊路徑差異?
    如何使用替換指令在GO MOD中解析模塊路徑差異?
    在使用GO MOD時,在GO MOD 中克服模塊路徑差異時,可能會遇到衝突,其中3個Party Package將另一個PAXPANCE帶有導入式套件之間的另一個軟件包,並在導入式套件之間導入另一個軟件包。如迴聲消息所證明的那樣: go.etcd.io/bbolt [&&&&&&&&&&&&&&&&...
    程式設計 發佈於2025-03-10
  • 為什麼使用Firefox後退按鈕時JavaScript執行停止?
    為什麼使用Firefox後退按鈕時JavaScript執行停止?
    導航歷史記錄問題:JavaScript使用Firefox Back Back 此行為是由瀏覽器緩存JavaScript資源引起的。要解決此問題並確保在後續頁面訪問中執行腳本,Firefox用戶應設置一個空功能。 警報'); }; alert('inline Alert')...
    程式設計 發佈於2025-03-10
  • 如何限制動態大小的父元素中元素的滾動範圍?
    如何限制動態大小的父元素中元素的滾動範圍?
    在交互式接口中實現垂直滾動元素的CSS高度限制問題:考慮一個佈局,其中我們具有與用戶垂直滾動一起移動的可滾動地圖div,同時與固定的固定sidebar保持一致。但是,地圖的滾動無限期擴展,超過了視口的高度,阻止用戶訪問頁面頁腳。 $("#map").css({ margin...
    程式設計 發佈於2025-03-10
  • HTML格式標籤
    HTML格式標籤
    HTML 格式化元素 **HTML Formatting is a process of formatting text for better look and feel. HTML provides us ability to format text without us...
    程式設計 發佈於2025-03-10
  • 如何為PostgreSQL中的每個唯一標識符有效地檢索最後一行?
    如何為PostgreSQL中的每個唯一標識符有效地檢索最後一行?
    postgresql:為每個唯一標識符在postgresql中提取最後一行,您可能需要遇到與數據集合中每個不同標識的信息相關的信息。考慮以下數據:[ 1 2014-02-01 kjkj 在數據集中的每個唯一ID中檢索最後一行的信息,您可以在操作員上使用Postgres的有效效率: id dat...
    程式設計 發佈於2025-03-10
  • 如何修復\“常規錯誤:2006 MySQL Server在插入數據時已經消失\”?
    如何修復\“常規錯誤:2006 MySQL Server在插入數據時已經消失\”?
    How to Resolve "General error: 2006 MySQL server has gone away" While Inserting RecordsIntroduction:Inserting data into a MySQL database can...
    程式設計 發佈於2025-03-10
  • 如何使用PHP將斑點(圖像)正確插入MySQL?
    如何使用PHP將斑點(圖像)正確插入MySQL?
    essue VALUES('$this->image_id','file_get_contents($tmp_image)')";This code builds a string in PHP, but the function call fil...
    程式設計 發佈於2025-03-10
  • 如何檢查對像是否具有Python中的特定屬性?
    如何檢查對像是否具有Python中的特定屬性?
    方法來確定對象屬性存在尋求一種方法來驗證對像中特定屬性的存在。考慮以下示例,其中嘗試訪問不確定屬性會引起錯誤: >>> a = someClass() >>> A.property Trackback(最近的最新電話): 文件“ ”,第1行, AttributeError: SomeClass...
    程式設計 發佈於2025-03-10
  • 如何在Java字符串中有效替換多個子字符串?
    如何在Java字符串中有效替換多個子字符串?
    在java 中有效地替換多個substring,需要在需要替換一個字符串中的多個substring的情況下,很容易求助於重複應用字符串的刺激力量。 However, this can be inefficient for large strings or when working with nu...
    程式設計 發佈於2025-03-10
  • 如何干淨地刪除匿名JavaScript事件處理程序?
    如何干淨地刪除匿名JavaScript事件處理程序?
    刪除匿名事件偵聽器將匿名事件偵聽器添加到元素中會提供靈活性和簡單性,但是當要刪除它們時,可以構成挑戰,而無需替換元素本身就可以替換一個問題。 element? element.addeventlistener(event,function(){/在這里工作/},false); 要解決此問題,請考...
    程式設計 發佈於2025-03-10
  • 為什麼我會收到MySQL錯誤#1089:錯誤的前綴密鑰?
    為什麼我會收到MySQL錯誤#1089:錯誤的前綴密鑰?
    mySQL錯誤#1089:錯誤的前綴鍵錯誤descript [#1089-不正確的前綴鍵在嘗試在表中創建一個prefix鍵時會出現。前綴鍵旨在索引字符串列的特定前綴長度長度,可以更快地搜索這些前綴。 了解prefix keys `這將在整個Movie_ID列上創建標準主鍵。主密鑰對於唯一識...
    程式設計 發佈於2025-03-10
  • 如何從PHP中的數組中提取隨機元素?
    如何從PHP中的數組中提取隨機元素?
    從陣列中的隨機選擇,可以輕鬆從數組中獲取隨機項目。考慮以下數組:; 從此數組中檢索一個隨機項目,利用array_rand( array_rand()函數從數組返回一個隨機鍵。通過將$項目數組索引使用此鍵,我們可以從數組中訪問一個隨機元素。這種方法為選擇隨機項目提供了一種直接且可靠的方法。
    程式設計 發佈於2025-03-10

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

Copyright© 2022 湘ICP备2022001581号-3