设计模式 
 
创建型模式 
提供了一种在创建对象的同时隐藏创建逻辑的方式
 
单例模式 饿汉方式 
在包被加载时创建
 
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,     } }