golang设计模式(1)单例模式

本文介绍了在Golang中如何实现单例模式,通过两种不同的实现方式详细讲解,并通过例子说明了在实际开发中如何避免单例模式的潜在问题,强调在不影响服务性能的情况下,推荐使用更合理的第二种实现方式。
摘要由CSDN通过智能技术生成

做软件开发工程师两三年了,接触到的第一种设计模式就是单例模式,记得当年第一份工作第一个任务就是用C语言写一个网络抓包的工具。那时候坐旁边的同事就问,你们两写的这个工具有用到什么设计模式吗?当时一脸懵,设计模式是个什么东西,那时候他说计算机专业有学过,但是看公司版本代码,他只看到了单例模式。从那时候开始我知道有设计模式这个事,学习也是从单例模式开始的。当然,设计模式中,单例模式也是最常用的一种。
golang也是我在第一家公司开始接触的,那个时候我不知道为什么好端端C++不用,非要用golang,让我们几个新来的学习golang,然后小组长带着我们做项目。虽然那时候用golang做的项目,没有涉及到多大的并发量,但是开发的时候确实是快,设计总体框架了以后我们按部就班的写代码。项目整体是个分布式的架构,用了多种语言代码,有C++、C#、java等。最后确实是我们几个新手用golang做的服务,相对来说比较的稳定,而且也开发效率高,bug也相对较少。从此golang就变成我非常感兴趣的一门语言。
进入主题,首先,单例模式说白了,就是在整个golang单体服务中,如果说把所有csdn博客比喻成一个服务,那么所有原创的文章都是单例的。转载出去的就不是单例的,如果转载后由文章加上对应的用户,如果将其封装起来,也是独一无二的。现在来看看集中golang单例模式的实现:

1、单实例只会被使用不会被赋值的时候。可以在对应package中定义实例对象,然后再init函数中对其赋初始值。注意对象名首字母需要大写,否则其他模块无法使用。实现可以如下:

package tsingleton
func init() {
    TestSingleton = &Singleton{"keqian"}
}

type Singleton struct {
    Name string
}

var TestSingleton *Singleton

调用的时候直接调用包里边的变量即可:

import "tsingleton"
psttestsigleton := tsingleton.TestSingleton 

在单例实例不会被赋值,前实例提供的方法是可重入的时候,这样子定义是最简单的。

2、单例实例在使用过程中,有可能会被赋值(理论上认为是有可能发生的,比如编码时候的失误),这时候需要提供一个方法来获取单例实例。实现可以如下:

package tsingleton
import (
    "fmt"
    "sync"
)

func init() {
    TestSingleton = &Singleton{"keqian"}
}

type Singleton struct {
    Name string
}

var TestSingleton *Singleton
var singletonMutex sync.Mutex

func NewSingleton() *Singleton {
    if TestSingleton == nil {
        singletonMutex.Lock()
        if TestSingleton == nil {
            TestSingleton = &Singleton{"keqian"}
        }
        singletonMutex.Unlock()
    }
    return TestSingleton
}

那么在使用的时候可以这样:

tsingleton.NewSingleton().Name //这里直接获取变量,实际应用中可能就是调用对应方法等其他操作。

注意,在使用的时候尽可能的直接用调用获取单例实例方法后接上要做的操作。这样可以防止在使用过程中无意的将变量赋值。比如:

psttestsigleton := tsingleton.NewSingleton()
strname := psttestsigleton.Name
...
psttestsigleton = nil
...
strname2 := psttestsigleton.Name 

这种情况下,就有可能出现问题。果然在调用的时候都用tsingleton.NewSingleton()就可以避免这个问题。

总结:在不影响服务性能的情况下,最好使用第二种实现,输入第一种实现比较简单,但是在开发过程中容易遇到各种坑,比如单例变量被赋值为空后没有修复的感知。第二种实现会比较合理一点,主要体现为开发者在使用的时候很明确这是一个单例实例,且不用担心会被异常赋值。如果单例实例会频繁地被用到,比如在一次完整服务调用流程会被使用多次,那么就要考虑设计上是否合理。如果别无它发,那也可以不用函数调用的方式,但是使用者在使用的时候需要注意,不要给单例赋值。

以下是几种常见的Golang设计模式: 1. 工厂模式(Factory Pattern):用于创建对象的模式,通过定义一个创建对象的接口来实现对象的实例化。 ```go type Shape interface { Draw() } type Circle struct{} func (c *Circle) Draw() { fmt.Println("Drawing a circle") } type Rectangle struct{} func (r *Rectangle) Draw() { fmt.Println("Drawing a rectangle") } type ShapeFactory struct{} func (sf *ShapeFactory) GetShape(shapeType string) Shape { if shapeType == "circle" { return &Circle{} } else if shapeType == "rectangle" { return &Rectangle{} } return nil } func main() { factory := &ShapeFactory{} circle := factory.GetShape("circle") circle.Draw() // 输出:Drawing a circle rectangle := factory.GetShape("rectangle") rectangle.Draw() // 输出:Drawing a rectangle } ``` 2. 单例模式(Singleton Pattern):确保一个类只有一个实例,并提供一个全局访问点。 ```go type Singleton struct{} var instance *Singleton func GetInstance() *Singleton { if instance == nil { instance = &Singleton{} } return instance } func main() { singleton1 := GetInstance() singleton2 := GetInstance() fmt.Println(singleton1 == singleton2) // 输出:true } ``` 3. 观察者模式(Observer Pattern):定义了一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都会得到通知并自动更新。 ```go type Subject struct { observers []Observer } func (s *Subject) Attach(observer Observer) { s.observers = append(s.observers, observer) } func (s *Subject) Notify() { for _, observer := range s.observers { observer.Update() } } type Observer interface { Update() } type ConcreteObserver struct{} func (co *ConcreteObserver) Update() { fmt.Println("Observer is updated") } func main() { subject := &Subject{} observer := &ConcreteObserver{} subject.Attach(observer) subject.Notify() // 输出:Observer is updated } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值