创建型模式
一、定义 :它提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 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")
注意事项
郑重声明:此文档仅用于学习交流使用,请勿用做商业用途。