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

單例設計模式

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

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]刪除
最新教學 更多>
  • 如何從Google API中檢索最新的jQuery庫?
    如何從Google API中檢索最新的jQuery庫?
    從Google APIS 問題中提供的jQuery URL是版本1.2.6。對於檢索最新版本,以前有一種使用特定版本號的替代方法,它是使用以下語法: https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js(google hosted...
    程式設計 發佈於2025-02-06
  • 如何使用Python的記錄模塊實現自定義處理?
    如何使用Python的記錄模塊實現自定義處理?
    使用Python的Loggging Module 確保正確處理和登錄對於疑慮和維護的穩定性至關重要Python應用程序。儘管手動捕獲和記錄異常是一種可行的方法,但它可能乏味且容易出錯。 解決此問題,Python允許您覆蓋默認的異常處理機制,並將其重定向為登錄模塊。這提供了一種方便而係統的方法來捕獲...
    程式設計 發佈於2025-02-06
  • 為什麼使用Firefox後退按鈕時JavaScript執行停止?
    為什麼使用Firefox後退按鈕時JavaScript執行停止?
    導航歷史記錄問題:JavaScript使用Firefox Back Back 此行為是由瀏覽器緩存JavaScript資源引起的。 To resolve this issue and ensure scripts execute on subsequent page visits, Firefox...
    程式設計 發佈於2025-02-06
  • 如何檢索SQL中每個用戶的最新登錄日期?
    如何檢索SQL中每個用戶的最新登錄日期?
    SQL查詢每個用戶的最後登錄記錄日期 問題: 假設數據庫表包含用戶登錄信息,我們如何檢索每個用戶的最後登錄日期?考慮到可能存在重複的登錄日期。 解決方案: 解決此問題有兩種常見方法: 方法一:使用INNER JOIN的子查詢 此方法利用子查詢來識別每個用戶的最後登錄日期,然後用於過濾主表: se...
    程式設計 發佈於2025-02-06
  • 如何有效處理Java中的時區轉換?
    如何有效處理Java中的時區轉換?
    跨時區的時區轉換 java.util.date類缺乏明確的時區分配。它的Tostring方法誤導了JVM的默認時區,導致混亂。為了避免這些陷阱,現代Java利用Java.Time軟件包進行更健壯的時間處理。 在Java.Time中轉換時區,指定一個時區並調用ZonedDateTime.now方...
    程式設計 發佈於2025-02-06
  • 為什麼我的燒瓶應用程序會拋出“ templatenotfound”錯誤,即使我的模板文件存在?
    為什麼我的燒瓶應用程序會拋出“ templatenotfound”錯誤,即使我的模板文件存在?
    故障排除flask的templatenotfound錯誤 在嘗試在flask中渲染模板,例如'home.html' ,您可能會遇到''''',您可能會遇到''' jinja2.exceptions.templateno...
    程式設計 發佈於2025-02-06
  • 刪除地圖條目是否會導致持有指針時的內存洩漏?
    刪除地圖條目是否會導致持有指針時的內存洩漏?
    [2一片指針可能會導致內存洩漏。這個問題將查詢擴展到地圖,特別是從持有的地圖中刪除條目是否會導致相似的行為。 檢查實現:確定此說法的真實性,讓我們調查GO的運行時:Runtime/Hashmap.go(function MapDelete( ))中的映射刪除的源代碼。檢查表明,刪除(#600,#60...
    程式設計 發佈於2025-02-06
  • 對象擬合:IE和Edge中的封面失敗,如何修復?
    對象擬合:IE和Edge中的封面失敗,如何修復?
    解決此問題,我們採用了一個巧妙的CSS解決方案來解決問題:高度:100%; 高度:auto ; 寬度:100%; //對於水平塊 ,使用絕對定位將圖像定位在中心,以object-fit:object-fit :cover in IE和edge消除了問題。現在,圖像將按比例擴展,保持所需的效果而不...
    程式設計 發佈於2025-02-06
  • 如何使用不同數量列的聯合數據庫表?
    如何使用不同數量列的聯合數據庫表?
    合併列數不同的表 當嘗試合併列數不同的數據庫表時,可能會遇到挑戰。一種直接的方法是在列數較少的表中,為缺失的列追加空值。 例如,考慮兩個表,表 A 和表 B,其中表 A 的列數多於表 B。為了合併這些表,同時處理表 B 中缺失的列,請按照以下步驟操作: 確定表 B 中缺失的列,並將它們添加到表的...
    程式設計 發佈於2025-02-06
  • OpenGL的屏幕外渲染如何工作?
    OpenGL的屏幕外渲染如何工作?
    在OpenGl中roendering:詳細的指南 framebuffers:讀取像素: glreadpixels允許我們檢索存儲在flamebuffer中的像素數據並將其傳輸到主內存中。 一種基本的OffScreen渲染方法涉及以下步驟:創建FrameBuffer: 使用glgenframebuf...
    程式設計 發佈於2025-02-06
  • 如何使用PHP將斑點(圖像)正確插入MySQL?
    如何使用PHP將斑點(圖像)正確插入MySQL?
    在嘗試將image存儲在mysql數據庫中時,您可能會遇到一個可能會遇到問題。本指南將提供成功存儲您的圖像數據的解決方案。 easudy values('$ this-> ; image_id','file_get_contents($ tmp_imag...
    程式設計 發佈於2025-02-06
  • 為什麼我的Mac OS X MySQL Server在不更新PID文件的情況下退出?
    為什麼我的Mac OS X MySQL Server在不更新PID文件的情況下退出?
    mySQL啟動錯誤:“服務器退出而無需更新PID文件”在Mac X 退出服務器,而無需更新PID文件此問題通常源於權限問題。以下是解決它的方法:檢查運行mysql Instances 如果找到一個實例,請終止它: 接下來,檢查/usr/usr/local/local/var/mysql/dire...
    程式設計 發佈於2025-02-06
  • 如何從JCHECKBOX行選擇中有效地從JTable中獲得選擇的行?
    如何從JCHECKBOX行選擇中有效地從JTable中獲得選擇的行?
    [2在第一列中使用JCHECKBOX進行JCHECKBOX,以進行行選擇。順序遍歷的效率很大。 傳統方法:Proposed Approach:Model-Based Tracking:Update a Set containing the selected row indices whenever ...
    程式設計 發佈於2025-02-06
  • CSS兒童選擇器:`>'和空間有什麼區別?
    CSS兒童選擇器:`>'和空間有什麼區別?
    `和一個空間? “ />`還有一個空間? CSS中的“ />
    程式設計 發佈於2025-02-06
  • 如何在整個HTML文檔中設計特定元素類型的第一個實例?
    如何在整個HTML文檔中設計特定元素類型的第一個實例?
    [2單獨使用CSS,整個HTML文檔可能是一個挑戰。 the:第一型偽級僅限於與其父元素中類型的第一個元素匹配。 以下CSS將使用添加的類樣式的第一個段落: }
    程式設計 發佈於2025-02-06

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

Copyright© 2022 湘ICP备2022001581号-3