设计模式
创建型模式
提供了一种在创建对象的同时隐藏创建逻辑
的方式
单例模式 饿汉方式
在包
被加载
时创建
1 2 3 4 5 6 7 8 9 10 package singletontype Singleton struct {} var instance *Singleton = &Singleton{}func GetInstance () *Singleton { return instance }
懒汉方式
在第一次使用时创建 - 使用最多,但非并发安全
,需要加锁
不加锁 1 2 3 4 5 6 7 8 9 10 11 12 13 14 package singletontype Singleton struct {} var instance *Singletonfunc GetInstance () *Singleton { if instance == nil { instance = &Singleton{} } return instance }
Mutex
double check
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package singletonimport "sync" type Singleton struct {} var instance *Singletonvar mutex sync.Mutexfunc GetInstance () *Singleton { if instance == nil { mutex.Lock() if instance == nil { instance = &Singleton{} } mutex.Unlock() } return instance }
Once 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package singletonimport "sync" type Singleton struct {} var instance *Singletonvar once sync.Oncefunc GetInstance () *Singleton { once.Do(func () { instance = &Singleton{} }) return instance }
工厂模式
建议返回非指针
的实例 - 意图为创建实例并调用其提供的方法,并非对实例进行更改
简单工厂模式
最常用
1 2 3 4 5 6 7 8 9 10 11 12 13 package factorytype Person struct { Name string Age int } func NewPerson (name string , age int ) *Person { return &Person{ Name: name, Age: age, } }
抽象工厂模式
与简单工厂模式的唯一区别:返回的是接口
而不是结构体
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package factoryimport "fmt" type Human interface { Greet() } type man struct { Name string Age int } func (m man) Greet() { fmt.Printf("My name is %s\n" , m.Name) } func NewHuman (name string , age int ) Human { return man{ Name: name, Age: age, } }
通过返回接口,实现多个工厂函数,返回不同的接口实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 package factoryimport ( "net/http" "net/http/httptest" ) type Doer interface { Do(req *http.Request) (*http.Response, error ) } func NewHTTPClient () Doer { return &http.Client{} } type mockHTTPClient struct {} func (m *mockHTTPClient) Do(req *http.Request) (*http.Response, error ) { recorder := httptest.NewRecorder() return recorder.Result(), nil } func NewMockHTTPClient () Doer { return &mockHTTPClient{} }
便于单元测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 func QueryUser (doer Doer) error { request, err := http.NewRequest("Gte" , "http://localhost:8080" , nil ) if err != nil { return err } _, err = doer.Do(request) if err != nil { return err } return nil } func TestQueryUser (t *testing.T) { doer := NewMockHTTPClient() if err := QueryUser(doer); err != nil { t.Errorf("Error: %s" , err) } }
工厂方法模式
简单工厂模式 - 依赖于唯一的工厂对象,如果新增一个工厂对象,需要修改工厂中的函数,耦合度很高
依赖于工厂函数
,通过实现工厂函数来创建多种工厂
由一群子类
来负责具体类的实例化,解耦
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package factorytype Person struct { name string age int } func NewPersonFactory (age int ) func (name string ) Person { return func (name string ) Person { return Person{ name: name, age: age, } } } func test () { newBaby := NewPersonFactory(1 ) baby := newBaby("John" ) newAdult := NewPersonFactory(18 ) adult := newAdult("Jane" ) }
结构型模式
关注类和对象的组合
策略模式
定义一组算法,将每个算法都封装
起来,并且它们之间可以互换
,最常见的场景 - 排序算法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 package mainimport "fmt" type IStrategy interface { do(int , int ) int } type add struct {} func (*add) do(a int , b int ) int { return a + b } type reduce struct {} func (*reduce) do(a int , b int ) int { return a - b } type Operator struct { strategy IStrategy } func (o *Operator) setStrategy(s IStrategy) { o.strategy = s } func (o *Operator) calculate(a, b int ) int { return o.strategy.do(a, b) } func main () { operator := Operator{} operator.setStrategy(&add{}) result := operator.calculate(1 , 2 ) fmt.Println(result) operator.setStrategy(&reduce{}) result = operator.calculate(1 , 2 ) fmt.Println(result) }
模板模式
定义一个操作中的算法骨架
,然后将一些步骤延迟
到子类中
将一个类中能够公共使用
的方法放置在抽象类
中实现
将不能公共使用的方法作为抽象方法,强制
子类去实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 package mainimport "fmt" type Cooker interface { fire() cooke() outFire() } func doCook (cooker Cooker) { cooker.fire() cooker.cooke() cooker.outFire() } type CommonCook struct {} func (CommonCook) fire() { fmt.Println("fire" ) } func (CommonCook) cooke() { } func (CommonCook) outFire() { fmt.Println("out fire" ) } type CookFish struct { CommonCook } func (CookFish) cooke() { fmt.Println("cook fish" ) } type CookMeat struct { CommonCook } func (CookMeat) cooke() { fmt.Println("cook meat" ) } func main () { doCook(CookFish{}) doCook(CookMeat{}) }
行为型模式
关注对象
之间的通信
代理模式
代理类中持有
被代理类的对象,并且两者实现同一接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 type Seller interface { sell(name string ) } type Station struct { stock int } func (s *Station) sell(name string ) { if s.stock > 0 { s.stock-- } } type StationProxy struct { station *Station } func (s *StationProxy) sell(name string ) { if s.station.stock > 0 { s.station.sell(name) } }
选项模式
创建一个带有默认值
的 struct 变量,并选择性
地修改其中一些参数的值,Go 函数形参不支持
默认值
支持传递多个参数
支持任意顺序
传递参数
支持默认值
符合 OCP
,扩展性强
适用场景:结构体参数很多 or 结构体参数经常变动
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 import "time" const ( defaultTimeout = 10 defaultCaching = false ) type options struct { caching bool timeout time.Duration } type Option interface { apply(*options) } type optionFunc func (*options) func (f optionFunc) apply(o *options) { f(o) } func WithTimeout (t time.Duration) Option { return optionFunc(func (o *options) { o.timeout = t }) } func WithCaching (c bool ) Option { return optionFunc(func (o *options) { o.caching = c }) } type Connection struct { addr string caching bool timeout time.Duration } func NewConnection (addr string , opts ...Option) *Connection { o := options{ caching: defaultCaching, timeout: defaultTimeout, } for _, option := range opts { option.apply(&o) } return &Connection{ addr: addr, caching: o.caching, timeout: o.timeout, } }