设计模式-创建型模式

创建型模式

一、定义 :它提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象

二、常见设计模式

1、单例模式:全局共享一个实例,且只需要初始化一次的场景
  • 恶汉模式:全局变量在包被加载时创建
package singleton
type singleton struct {
}
var ins *singleton = &singleton{}
func GetInsOr() *singleton {
    return ins
}
  • 懒汉模式:全局变量在第一次使用时创建一次。
package singleton
type singleton struct {
}

var ins *singleton
func GetInsOr() *singleton {
    if ins == nil {
        ins = &singleton{}
    }
    return ins
}
  • 懒汉模式并发安全问题:
package singleton
type singleton struct {
}
var ins *singleton
var mu sync.Mutex
func GetInsOr() *singleton {
    if ins == nil {
        mu.Lock()
        if ins == nil {
            ins = &singleton{}
        }
    } 
    return ins
}

  • 使用 once.Do 确保ins 实例 全局只被创建一次 ;确保当同时有多个创建动作时,只有一个创建动作被执行
package singleton
type singleton struct {}
var ins *singleton
var once sync.Once
func GetInsOr() *singleton {
    once.Do(func() {
        ins = &singleton{}
    })
    return ins
}
2、简单工厂模式:方法 返回 实例

why:和 p :=&Person{}相比 ,确保我们创建的实例具有需要的参数,进而保证实例的方法可以按预期执行。

type Person struct {
    Name string
    Age int
}
func (p Person) Greet() {
    fmt.Printf("Hi! My name is %s", p.Name)
}
func NewPerson(name string, age int) *Person{
    return &Person {
        Name: name,
        Age: age,
    }
}

3、抽象工厂模式:方法 返回 接口 (区别)

why:在你不公开内部实现的情况下,让调用者使用你提供的各种功能。

通过返回接口,我们还可以实现多个工厂函数,来返回不同的接口实现

type person struct {
    Name string
    Age int
}
type Person interface {
    Greet()
}
func (p person) Greet() {
    fmt.Printf("Hi! My name is %s", p.name)
}
func NewPerson(name string, age int) Person{
    return person{
        name: name, 
        age: age, 
    }
}
func NewPerson2(name string, age int) Person{
    return person{
        name: name, 
        age: age, 
    }
}
// We define a Doer interface, that has the method signature
// of the `http.Client` structs `Do` method
type Doer interface {
  Do(req *http.Request) (*http.Response, error)
}
// This gives us a regular HTTP client from the `net/http` package
func NewHTTPClient() Doer {
  return &http.Client{}
}

type mockHTTPClient struct{}
func (*mockHTTPClient) Do(req *http.Request) (*http.Response, error) {
  // The `NewRecorder` method of the httptest package gives us
  // a new mock request generator
  res := httptest.NewRecorder()

  // calling the `Result` method gives us
  // the default empty *http.Response object
  return res.Result(), nil
}
// This gives us a mock HTTP client, which returns
// an empty response for any request sent to it
func NewMockHTTPClient() Doer {
  return &mockHTTPClient{}
}

NewHTTPClient和NewMockHTTPClient都返回了同一个接口类型 Doer,这使得二者可以互换使用。当你想测试一段调用了 Doer 接口 Do 方法的代码时,这一点特别有用。因为你可以使用一个 Mock 的 HTTP 客户端,从而避免了调用真实外部接口可能带来的失败。

func QueryUser(doer Doer) error {
  req, err := http.NewRequest("Get", "http://iam.api.marmotedu.com:8080/v1/secrets", nil)
  if err != nil {
    return err
  }
  _, err := doer.Do(req)
  if err != nil {
    return err
  }
  return nil
}

其测试用例为:

func TestQueryUser(t *testing.T) {
  doer := NewMockHTTPClient()
  if err := QueryUser(doer); err != nil {
    t.Errorf("QueryUser failed, err: %v", err)
  }
}

4、工厂方法模式:依赖工厂函数,我们可以通过实现工厂函数来创建多种工厂(返回的是函数 )

type Person struct {
    name string
    age int
}
// 创建具有默认年龄的工厂
func NewPersonFactory(age int) func(name string) Person {
    sum := age + 10 
    return func(name string) Person {
        return Person{
            name: name,
            age: age,
        }
    }
}
newBaby := NewPersonFactory(1)
baby := newBaby("john")
newTeenager := NewPersonFactory(16)
teen := newTeenager("jill")


注意事项

郑重声明:此文档仅用于学习交流使用,请勿用做商业用途。

你可能感兴趣的:(go,设计模式,创建型模式)