设计模式-创建型模式

news/2024/7/7 18:43:00

创建型模式

一、定义 :它提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 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")


注意事项

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


http://lihuaxi.xjx100.cn/news/74302.html

相关文章

CDH大数据平台 16Cloudera Manager Console之Sentry权限配置和测试(markdown新版)

一、Sentry权限控制和开启 启用 Sentry 权限控制 参考:https://docs.cloudera.com/documentation/enterprise/latest/topics/sentry.html https://docs.cloudera.com/documentation/enterprise/latest/topics/sg_hdfs_sentry_sync.html#xd_583c10bfdbd326ba–69a…

教育机构如何做到线上、线下共同发展

在这个知识付费时代,决定教育机构未来发展的主战场,早已不仅只在线下,而是蔓延到了线上的用户流量之争。 很多教育机构都及时抓住了机遇,通过像创客匠人这样的内容付费技术服务商,搭建属于自己的在线教育平台&#xf…

java判断字符串不为空或null

注意:要先检查str不为null,否则在一个null值上调length()方法会出现错误。(使用这行代码)if (str ! null && str.length() ! 0); 1、空串""是长度为0的字符串,它有自己的串长度(0&#x…

ESP8266-Arduino网络编程实例-异步TCP服务器

异步TCP服务器 本次实例将如何通过ESPAsyncTCP库实现一个简单的异步服务器。 实例主要由如下步骤组成: WiFi连接创建TCP服务器注册客户连接回调函数。回调函数包含如下处理情形: 客户端数据处理错误处理连接断开处理超时处理启动TCP服务器1、硬件准备 ESP8266 NodeMCU开发板…

【Linux】基本的指令(二)

大家好我是沐曦希💕 文章目录1.rmdir指令 && rm 指令(重要)2.man指令(重要)3.cp指令(重要)4.mv指令5.cat指令6.more指令7.less指令8.head指令9.tail指令head和tail结合看中间4.写在最后…

AST实战|AST入门与实战课程随堂笔记1010

关注它,不迷路。 本文章中所有内容仅供学习交流,不可用于任何商业用途和非法用途,否则后果自负,如有侵权,请联系作者立即删除!1. 作业地址https://t.zsxq.com/06bmmEynQ2. 混淆代码分析拿到一段混淆的…

深度神经网络算法有哪些,深度神经网络算法原理

1、谁家的GPU服务器更适合深度学习? 蓝海大脑深度学习GPU服务器采用 Gluster 分布式架构设计提供大存储量⌄拥有开放融合的特性和超能运算的能力。支持多块AMD、英伟达NVIDIA、英特尔Intel GPU显卡,提供出色的静音效果和完美的温控系统。服务于深度学习…

计算机网络基础 ---- 静态路由----详解

一、静态路由: 概述: 由管理员手工配置的,是单向的,拓扑关系缺乏灵活性; 优点: 配置灵活,管理员手工配置,节省链路开销; 缺点: 当拓扑发生改变时,需要管理员去每台路由…