从今天开始,学习go语言的设计模式,之前学习java的时候,都没有好好学习一下设计模式,现在从go语言开始把24种常见设计模式从头到尾学习一遍。
单例模式简介
单例模式用于确保一个类只有一个实例,并提供一个全局访问点来获取该实例,但是go语言中没有类的概念,而是用的结构体,以下讲的所有都是基于go语言来讲的。在单例模式下,保证了这个结构体只能被初始化一次。单例模式又分为饿汉模式和懒汉模式,这两种模式的根本区别就是实例的初始化时机。
1、饿汉模式
在包被导入的时候,就初始化了这个结构体的实例。
package singleton
type Singleton struct{
Name string
}
var singleton = &Singleton{Name:"张三"}
func GetInstance() *Singleton{
return singleton
}
2、懒汉模式
在第一次需要使用这个结构体的实例的时候,这个实例才被初始化。
package singleton
import (
"sync"
)
type Singleton struct{
Name string
}
var singleton *Singleton
//使用sync.Once来确保线程安全
var once sync.Once
func GetInstance() *Singleton{
once.Go(func (){
singleton = &Singleton{Name:"张三"}
})
return singleton
}
sync.Once只提供一个Do方法,这个方法只会执行一次。让我们来试一试:
package main
import(
"sync"
"fmt"
)
type Singleton struct{
Name string
}
var singleton *Singleton
//使用sync.Once来确保线程安全
var once sync.Once
func GetInstance() *Singleton{
fmt.Println("进入到函数,在once.Go外面执行")
once.Do(func (){
fmt.Println("进入到once.Go里面执行")
singleton = &Singleton{Name:"张三"}
})
return singleton
}
func main(){
ins1 := GetInstance()
ins2 := GetInstance()
fmt.Println(ins1)
fmt.Println(ins2)
}
//输出:
//进入到函数,在once.Go外面执行
//进入到once.Go里面执行
//进入到函数,在once.Go外面执行
//&{张三}
//&{张三}
我们可以看到,在调用了两次GetInstance函数后,once.Do方法只执行了一次。
练手题目
这里我们使用的题目都来自于代码随想录的卡码网,大家也可以自己去上面练习。
题目简介:
【设计模式专题之单例模式】1.小明的购物车
时间限制:1.000S 空间限制:256MB
题目描述
>小明去了一家大型商场,拿到了一个购物车,并开始购物。请你设计一个购物车管理器,记录商品添加到购物车的信息(商品名称和购买数量),并在购买结束后打印出商品清单。(在整个购物过程中,小明只有一个购物车实例存在)。
输入描述
>输入包含若干行,每行包含两部分信息,分别是商品名称和购买数量。商品名称和购买数量之间用空格隔开。
输出描述
>输出包含小明购物车中的所有商品及其购买数量。每行输出一种商品的信息,格式为 "商品名称 购买数量"。
输入示例
>Apple 3
>Banana 2
>Orange 5
输出示例
>Apple 3
>Banana 2
>Orange 5
提示信息
>本道题目请使用单例设计模式:
>使用私有静态变量来保存购物车实例。
>使用私有构造函数防止外部直接实例化。
代码比较简单,使用懒汉式。直接上代码:
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
"sync"
)
type ShoppingCar struct {
Product []string
Numb []int
}
var shoppingCar *ShoppingCar
var once sync.Once
func getInstance() *ShoppingCar {
once.Do(func() {
shoppingCar = &ShoppingCar{Product: []string{}, Numb: []int{}}
})
return shoppingCar
}
func main() {
ins1 := getInstance()
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
text := scanner.Text()
if text == "done" {
break
}
//将输入按空格分割为字符串切片,split[0]是商品名称,split[1]是购买数量
split := strings.Split(text, " ")
numb, _ := strconv.Atoi(split[1])
ins1.Product = append(ins1.Product, split[0])
ins1.Numb = append(ins1.Numb, numb)
}
for index, _ := range ins1.Product {
fmt.Printf("%s %d \n", ins1.Product[index], ins1.Numb[index])
}
}