2016-12-21 21 views
4

EDITED已解决:如何在GoLang中创建单例DBManager类。如何在GoLang中创建单例DB类

我介绍了几个如何创建单身人士的代码示例,但我希望有这些方法,并在他们的单身人士参考调用他们。我的代码如下

package dbprovider 

import (
    "github.com/jinzhu/gorm" 
    _"github.com/jinzhu/gorm/dialects/sqlite" 
    "rest/article" 
    "log" 
) 

type DBOperations interface { 
    AddArticle(article *article.Article) 
} 

type DBManager struct { 
    db   *gorm.DB 
    isInitialized bool 
} 

var dbManagerInstance = new() 

func GetDBManager() DBManager { 
    return dbManagerInstance 
} 

func new() DBManager { 
    localDbRef, err := gorm.Open("sqlite3", "../articles.db") 
    if (err != nil) { 
     panic("Error initializing db") 
    } else { 
     log.Print("DB Initialized successfully") 
    } 
    return DBManager{db:localDbRef, isInitialized:true} 
} 

func (dbManager DBManager) AddArticle(article article.Article) (err error) { 
    if (dbManager.isInitialized) { 
     tx := dbManager.db.Begin() 
     //dbManager.db.NewRecord(article) 
     //dbManager.db.Commit() 
     tx.NewRecord(article) 
     tx.Commit() 
     errs := dbManager.db.GetErrors() 
     if (len(errs) > 0) { 
      err = errs[0] 
     } else { 
      log.Print("No error in this transactions") 
     } 

    } 
    return 
} 

有了新的答案我已经更新了这个问题,包括回答。但我有几个疑问。创建(..)

回答

7

一种方法是使用方法创建导出的接口,并使实现类型不导出。创建接口类型的全局变量,并使用包init()函数对其进行初始化。你不需要任何同步,因为包init()函数只能安全运行一次。

程序包init()函数在运行时自动执行一次,然后才能引用该程序包中的任何内容。有关详情,请参阅Spec: Package initialization

例如:

package dbprovider 

type Manager interface { 
    AddArticle(article *article.Article) error 
    // Add other methods 
} 

type manager struct { 
    db *gorm.DB 
} 

var Mgr Manager 

func init() { 
    db, err := gorm.Open("sqlite3", "../articles.db") 
    if err != nil { 
     log.Fatal("Failed to init db:", err) 
    } 
    Mgr = &manager{db: db} 
} 

func (mgr *manager) AddArticle(article *article.Article) (err error) { 
    mgr.db.Create(article) 
    if errs := mgr.db.GetErrors(); len(errs) > 0 { 
     err = errs[0] 
    } 
    return 
} 

使用它:

import "dbprovider" 

if err := dbprovider.Mgr.AddArticle(someArticle); err != nil { 
    // Handle error 
} 

你也可以做到这一点没有init()功能,如:

var Mgr = newManager() 

func newManager() Manager { 
    db, err := gorm.Open("sqlite3", "../articles.db") 
    if err != nil { 
     log.Fatal("Failed to init db:", err) 
    } 
    return &manager{db: db} 
} 

有了这个,你可以决定使newManager()导出并且您的包的用户可以决定使用sh例如Mgr实例,或者他们可以创建另一个Manager,例如,用于测试目的。

注:Mgr是导出的全局变量,并且可以由其它包(例如dbprovider.Mgr = nil)的新值分配给它。如果你想避免这种情况,你必须使它导出,并为其提供“吸气”功能,例如:

var mgr = newManager() 

func Mgr() Manager { return mgr } 

,并用它:

err := dbprovider.Mgr().AddArticle(someArticle) 
+0

从那里这个init方法越来越叫什么名字? – sector11

+0

@ sector11包'init()'函数在运行时自动执行一次,然后才能引用包中的任何内容。见编辑的答案。 – icza

+0

获取不能使用localDbRef(类型* gorm.DB)作为字段值中的类型gorm.DB – sector11