您现在的位置是:首页 >学无止境 >Go常用设计模式网站首页学无止境
Go常用设计模式
简介Go常用设计模式
单例模式
饿汉模式
饿的要死就先吃,上来就给你初始化
package instance
type instance struct{}
// 饿汉,此包引入就初始化完成,不管你用不用,反正我是放到内存里去了
var i instance = instance{}
func getInstance() instance {
return i
}
懒汉模式
等我感觉要死了再吃,就是我确定要用到,才会去实例化
package instance
import "sync"
type instance struct{}
var i *instance
var mu sync.Locker
// 确定使用时,才初始化,需要加锁保证并发安全
func getInstance() *instance {
mu.Lock()
if i == nil {
i = &instance{}
}
mu.Unlock()
return i
}
优雅进阶版
package instance
import "sync"
type instance struct{}
var i *instance
var once sync.Once
func getInstance() *instance {
// 确实看起来舒服点,使用 once 保证只初始化一次
once.Do(func() {
i = &instance{}
})
return i
}
工厂模式
简单工厂
返回一个具体的实例
package main
type bird struct {
name string
}
// NewBigBird 工厂模式的好处在于不会让你忘记传参数
func NewBigBird(name string) bird {
return bird{
name: name,
}
}
// BAD 这啥鸟?
var b = bird{}
// GOOD
var c = NewBigBird("百灵鸟")
抽象工厂
和简单工厂的区别在于其返回的是接口类型
package main
import "fmt"
type Bird interface {
fly()
}
type bird struct {
name string
}
func (b bird) fly() {
fmt.Printf("%s 在飞", b.name)
}
// NewBigBird 返回的是接口类型
func NewBigBird(name string) Bird {
return bird{
name: name,
}
}
工厂方法
工厂方法 提供创建实例的方法,由外部决定是否创建,或者创建的(规格),适用于多规格的产品,比较灵活
package main
import "fmt"
type Bird interface {
fly()
}
type bird struct {
name string
color string
}
func (b bird) fly() {
fmt.Printf("%s %s 在飞
", b.color, b.name)
}
func NewBigBird(name string) func(color string) bird {
return func(color string) bird {
return bird{
name: name,
color: color,
}
}
}
func newReadBird(name string) bird {
return bird{
name: name,
color: "红色",
}
}
func newBlueBird(name string) bird {
return bird{
name: name,
color: "蓝色",
}
}
func newBird(name, color string) bird {
return bird{
name: name,
color: color,
}
}
func main() {
//1 工厂方法 提供创建实例的方法,由外部决定是否创建,或者创建的(规格),适用于多规格的产品,比较灵活
register := NewBigBird("喜鹊")
read := register("红色")
blue := register("蓝色")
read.fly()
blue.fly()
//2 简单工厂 在来个绿喜鹊 还需要创建 newGreen
read2 := newReadBird("喜鹊")
blue2 := newBlueBird("喜鹊")
read2.fly()
blue2.fly()
//3 比2稍微方便点,但是喜鹊是重复的参数
read3 := newBird("喜鹊", "红色")
blue3 := newBird("喜鹊", "蓝色")
read3.fly()
blue3.fly()
}
策略模式
主要是对算法(策略)的封装,根据不同场景使用不同的策略
package main
import "fmt"
type Strategy interface {
Do(money float64) float64
}
type normal struct {
}
type strategy51 struct {
}
// Do 劳动节5折
func (s strategy51) Do(money float64) float64 {
return money * 0.5
}
func (n normal) Do(money float64) float64 {
return money
}
type Goods struct {
strategy Strategy
}
func (g *Goods) setStrategy(s Strategy) {
g.strategy = s
}
func (g *Goods) getPrice(money float64) float64 {
return g.strategy.Do(money)
}
func main() {
g := Goods{}
//平常购买
g.setStrategy(normal{})
fmt.Println(g.getPrice(100))
//劳动节购
g.setStrategy(strategy51{})
fmt.Println(g.getPrice(100))
}
模板模式
将共同点抽离生成模板类,可变点强制子类去实现
package main
import "fmt"
type IStudent interface {
getSchool() string
getName() string
}
type SchoolTemplate struct {
}
// 同一个学校的
func (s SchoolTemplate) getSchool() string {
return "黄埔军校"
}
type Student struct {
Name string
SchoolTemplate
}
// 强制实现
func (s Student) getName() string {
return s.Name
}
func introduce(i IStudent) {
fmt.Printf("我叫%s,来自%s
", i.getName(), i.getSchool())
}
/*
*
由于小明和小白是一个学校的,抽离出学校模板类 SchoolTemplate
姓名不同,交给 Student 去实现
*/
func main() {
s := Student{Name: "小明"}
b := Student{Name: "小白"}
introduce(s)
introduce(b)
}
代理模式
代理模式对被代理的对象进行访问控制,把主机看做一个类,那么路由器就是代理者,代理者可以决定是否对其开放网络,和获取主机网络的具体信息
package main
import "fmt"
type Computer interface {
Connect()
}
type Proxy struct {
computer Computer
}
type Network struct {
}
func (n Network) Connect() {
fmt.Println("连接网络")
}
func (p Proxy) Connect(Ip string) {
// 对被代理的网络连接进行访问控制
if Ip == "6.6.6.6" {
fmt.Println("黑名单,禁止连接")
return
}
p.computer.Connect()
}
func main() {
proxy := Proxy{computer: Network{}}
proxy.Connect("6.6.6.6")
proxy.Connect("5.5.5.5")
}
选项模式
不管什么方式,都应该提供一个最佳配置的生成
选项模式是指 example3
example1
- 生成的方法有点多(newDefaultExample,newExample)
package main
import "fmt"
var (
aDefault = "a"
bDefault = "b"
cDefault = "c"
dDefault = "d"
eDefault = "e"
)
type example struct {
a string
b string
c string
d string
e string
}
func newDefaultExample() example {
return example{
a: aDefault,
b: bDefault,
c: cDefault,
d: dDefault,
e: eDefault,
}
}
func newExample(a, b, c, d, e string) example {
return example{
a: a,
b: b,
c: c,
d: d,
e: e,
}
}
func main() {
fmt.Println(newDefaultExample())
fmt.Println(newExample("1", "2", "3", "4", "5"))
}
example2
- 在example1的基础上,减少了生成方式(newDefaultExample),newExample 由 外部传入的参数对象决定生成的配置
- 但是参数对象生成的方式还是有点多(newDefaultOpt,options{})
- (options) 选项填的还是有点多,希望没填选项就使用最佳默认值(请看example3)
package main
import "fmt"
var (
aDefault = "a"
bDefault = "b"
cDefault = "c"
dDefault = "d"
eDefault = "e"
)
type example struct {
a string
b string
c string
d string
e string
}
type options struct {
a string
b string
c string
d string
e string
}
func newDefaultOpt() options {
return options{
a: "a1",
b: "b1",
c: "c1",
d: "d1",
e: "e1",
}
}
func newExample(opt options) example {
return example{
a: opt.a,
b: opt.b,
c: opt.c,
d: opt.d,
e: opt.e,
}
}
/*
*
在example1的基础上,减少了创建函数,外部传入的参数决定生成struct
但是创建选项的函数有多个
*/
func main() {
fmt.Println(newExample(newDefaultOpt()))
// 选项填的还是有点多,希望没填选项就使用最佳默认值(请看example3)
fmt.Println(newExample(options{
a: "a2",
b: "b2",
c: "c2",
d: "d2",
e: "e2",
}))
}
example3
- 提供了统一的入口,生成方式就一个
- 提供了最佳默认配置
- 外部设置了就覆盖默认配置选项,不设置就使用最佳默认配置中的选项信息
- 这个比 example1,example2 更灵活,也更复杂,参数不多不建议,但参数多的话,强烈建议
package main
import "fmt"
var (
aDefault = "a"
bDefault = "b"
cDefault = "c"
dDefault = "d"
eDefault = "e"
)
type example struct {
a string
b string
c string
d string
e string
}
type options struct {
a string
b string
c string
d string
e string
}
// IOptions 提供往配置上设置参数值的方法
type IOptions interface {
apply(opt *options)
}
type optionsFunc func(option *options)
func (f optionsFunc) apply(opt *options) {
f(opt)
}
func withA(a string) IOptions {
return optionsFunc(func(option *options) {
option.a = a
})
}
func withB(b string) IOptions {
return optionsFunc(func(option *options) {
option.b = b
})
}
// 提供了统一的入口,生成方式就一个
// opt 提供了往配置上设置参数值的方法
// 这个比 example1,example2 更灵活,也更复杂,参数不多不建议,但参数多的话,强烈建议
func newExample(opt ...IOptions) example {
// 提供了最佳默认配置
config := &options{
a: "a",
b: "b",
c: "c",
d: "d",
e: "e",
}
// 外部设置了就覆盖默认配置选项,不设置就使用最佳默认配置选项中的信息
for _, o := range opt {
o.apply(config)
}
return example{
a: config.a,
b: config.b,
c: config.c,
d: config.d,
e: config.e,
}
}
func main() {
fmt.Println(newExample())
fmt.Println(newExample(withA("a1"), withB("b2")))
}
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。