详解Go语言设计模式之单例模式_第1页
详解Go语言设计模式之单例模式_第2页
详解Go语言设计模式之单例模式_第3页
详解Go语言设计模式之单例模式_第4页
详解Go语言设计模式之单例模式_第5页
已阅读5页,还剩1页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第详解Go语言设计模式之单例模式目录单例模式的概念单例模式结构单例模式的使用场景单例模式例子:特殊的计数器第一个单元测试单例模式实现单例模式优缺点

单例模式的概念

单例模式很容易记住。就像名称一样,它只能提供对象的单一实例,保证一个类只有一个实例,并提供一个全局访问该实例的方法。

在第一次调用该实例时被创建,然后在应用程序中需要使用该特定行为的所有部分之间重复使用。

单例模式结构

单例模式的使用场景

你会在许多不同的情况下使用单例模式。比如:

当你想使用同一个数据库连接来进行每次查询时当你打开一个安全Shell(SSH)连接到一个服务器来做一些任务时。而不想为每个任务重新打开连接如果你需要限制对某些变量或空间的访问,你可以使用一个单例作为作为这个变量的门(在Go中使用通道可以很好地实现)如果你需要限制对某些空间的调用数量,你可以创建一个单例实例使得这种调用只在可接受的窗口中进行

单例模式还有跟多的用途,这里只是简单的举出一些。

单例模式例子:特殊的计数器

我们可以写一个计数器,它的功能是用于保存它在程序执行期间被调用的次数。这个计数器的需要满足的几个要求:

当之前没有创建过计数器count时,将创建一个新的计数器count=0如果已经创建了一个计数器,则返回此实例实际保存的count数如果我们调用方法AddOne一次,计数count必须增加1

在这个场景下,我们需要有3个测试来坚持我们的单元测试。

第一个单元测试

与Java或C++这种面向对象语言中不同,Go实现单例模式没有像静态成员的东西(通过static修饰),但是可以通过包的范围来提供一个类似的功能。

首先,我们要为单例对象编写包的声明:

packagesingleton

typeSingletonstruct{

countint

varinstance*Singleton

funcinit(){

instance=Singleton{}

funcGetInstance()*Singleton{

returnnil

func(s*Singleton)AddOne()int{

return0

然后,我们通过编写测试代码来验证我们声明的函数:

packagesingleton

import(

"testing"

funcTestGetInstance(t*testing.T){

count:=GetInstance()

ifcount==nil{

t.Error("Anewconnectionobjectmusthavebeenmade")

expectedCounter:=count

currentCount:=count.AddOne()

ifcurrentCount!=1{

t.Errorf("Aftercallingforthefirsttimetocount,thecountmustbe1butitis%d\n",currentCount)

count2:=GetInstance()

ifcount2!=expectedCounter{

t.Error("Singletoninstancesmustbedifferent")

currentCount=count2.AddOne()

ifcurrentCount!=2{

t.Errorf("Aftercalling'AddOne'usingthesecondcounter,thecurrentcountmustbe2butwas%d\n",currentCount)

}

第一个测试是检查是显而易见,但在复杂的应用中,其重要性也不小。当我们要求获得一个计数器的实例时,我们实际上需要得到一个结果。

我们把对象的创建委托给一个未知的包,而这个对象在创建或检索对象时可能失败。我们还将当前的计数器存储在变量expectedCounter中,以便以后进行比较。即:

currentCount:=count.AddOne()

ifcurrentCount!=1{

t.Errorf("Aftercallingforthefirsttimetocount,thecountmustbe1butitis%d\n",currentCount)

}

运行上面的代码:

$gotest-v-run=GetInstance.

===RUNTestGetInstance

singleton_test.go:12:Anewconnectionobjectmusthavebeenmade

singleton_test.go:19:Aftercallingforthefirsttimetocount,thecountmustbe1butitis0

singleton_test.go:31:Aftercalling'AddOne'usingthesecondcounter,thecurrentcountmustbe2butwas0

---FAIL:TestGetInstance(0.00s)

FAIL/yuzhoustayhungry/GoDesignPattern/singleton0.412s

单例模式实现

最后,我们必须实现单例模式。正如我们前面提到的,通常做法是写一个静态方法和实例来检索单例模式实例。

在Go中,没有static这个关键字,但是我们可以通过使用包的范围来达到同样的效果。

首先,我们创建一个结构体,其中包含我们想要保证的对象在程序执行过程中成为单例的对象。

packagesingleton

typeSingletonstruct{

countint

varinstance*Singleton

funcinit(){

instance=Singleton{}

funcGetInstance()*Singleton{

ifinstance==nil{

instance=new(Singleton)

returninstance

func(s*Singleton)AddOne()int{

s.count++

returns.count

}

我们来分析一下这段代码的差别,在Java或C++语言中,变量实例会在程序开始时被初始化为NULL。但在Go中,你可以将结构的指针初始化为nil,但不能将一个结构初始化为nil(相当于其他语言的NULL)。

所以varinstance*singleton*这一语句定义了一个指向结构的指针为nil,而变量称为instance。

我们创建了一个GetInstance方法,检查实例是否已经被初始化(instance==nil),并在已经分配的空间中创建一个实例instance=new(singleton)。

Addone()方法将获取变量实例的计数,并逐个加1,然后返回当前计数器的值。

再一次运行单元测试代码:

$gotest-v-run=GetInstance.

===RUNTestGetInstance

---PASS:TestGetInstance(0.00s)

ok/yuzhoustayhungry/GoDesignPattern/singleton0.297s

单例模式优缺点

优点:

你可以保证一个类只有一个实例。你获得了一个指向该实例的全局访问节点。仅在首次请求单例对象时对其进行初始化。

缺点:

违反了单一职责原则。该模式同时解决了两个问题。单例模式可能掩盖不良设计,比如程序各组件之间相互了解过多等。该模式在多线程环境下需要进行特殊

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论