创建型模式特点:创建对象的同时隐藏创建逻辑
1.单例模式。适用场景:全局共享一个实例,且只需要被初始化一次的场景。eg:数据库,全局配置,全局任务池
单例模式分为,1.懒汉模式(第一次使用时加载) 缺点:每次使用时要判断实例是否存在,不存在才创建,而且非并发安全的。 2.饿汉模式(全局加载时被创建) 缺点:创建实例耗时过长会导致启动过慢
//饿汉模式
type singleton struct {
}
var ins *singleton = &singleton{}
func GetInsOr() *singleton {
return ins
}
//懒汉模式
type singleton struct {
}
var ins *singleton
func GetInsOr() *singleton {
if ins == nil {
ins = &singleton{}
}
return ins
}
//解决懒汉模式并发安全 只执行一次sync.Once
import (
"sync"
)
type singleton struct {
}
var ins *singleton
var once sync.Once
func GetInsOr() *singleton {
once.Do(func() {
ins = &singleton{}
})
return ins
}
2.工厂模式。使用场景:代码简洁
//简单模式 定义类
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,
}
}
//抽象模式 定义接口
type Person interface {
Greet()
}
type person struct {
name string
age int
}
func (p person) Greet() {
fmt.Printf("Hi! My name is %s", p.name)
}
// Here, NewPerson returns an interface, and not the person struct itself
func NewPerson(name string, age int) Person {
return person{
name: name,
age: age,
}
}
结构型模式特点:关注类和对象的组合
3.策略模式 定义一组方法,将算法封装起来,并且使他们之间可以互换。
定义一些独立的类来封装不同的算法,每一个类封装一个具体的算法(即策略)。
// 定义接口 然后每一种计算方式类作为一种策略 都实现接口中的do方法
// 定义一个策略类
type IStrategy interface {
do(int, int) int
}
// 策略实现:加
type add struct{}
func (*add) do(a, b int) int {
return a + b
}
// 策略实现:减
type reduce struct{}
func (*reduce) do(a, b int) int {
return a - b
}
// 具体策略的执行者
type Operator struct {
strategy IStrategy
}
// 设置策略
func (operator *Operator) setStrategy(strategy IStrategy) {
operator.strategy = strategy
}
// 调用策略中的方法
func (operator *Operator) calculate(a, b int) int {
return operator.strategy.do(a, b)
}
4.模板模式:两个主要特征(继承和多态--个人理解),一是要继承算法骨架,达到复用的目的;二是具体的算法步骤在子类中实现,达到扩展的目的。
package template
import "fmt"
//定义接口
type Cooker interface {
fire()
cooke()
outfire()
}
// 类似于一个抽象类
type CookMenu struct {
}
func (CookMenu) fire() {
fmt.Println("开火")
}
// 做菜,交给具体的子类实现
func (CookMenu) cooke() {
}
func (CookMenu) outfire() {
fmt.Println("关火")
}
// 封装具体步骤,因为入参是实现定义的接口的函数,如果入参重新定义了方法就是就实现类继承的
func doCook(cook Cooker) {
cook.fire()
cook.cooke()
cook.outfire()
}
type XiHongShi struct {
CookMenu
}
func (*XiHongShi) cooke() {
fmt.Println("做西红柿")
}
type ChaoJiDan struct {
CookMenu
}
func (ChaoJiDan) cooke() {
fmt.Println("做炒鸡蛋")
}
行为型模式:特点是关注对象之间的通信
5.代理模式 为另一个对象提供一个替身或者占位符,以控制对这个对象的访问
场景:售票窗口和火车站都实现了售票的方法,售票窗口可以代理火车站的售票
package proxy
import "fmt"
type Seller interface {
sell(name string)
}
// 火车站
type Station struct {
stock int //库存
}
func (station *Station) sell(name string) {
if station.stock > 0 {
station.stock--
fmt.Printf("代理点中:%s买了一张票,剩余:%d \n", name, station.stock)
} else {
fmt.Println("票已售空")
}
}
// 火车代理点
type StationProxy struct {
station *Station // 持有一个火车站对象
}
func (proxy *StationProxy) sell(name string) {
if proxy.station.stock > 0 {
proxy.station.stock--
fmt.Printf("代理点中:%s买了一张票,剩余:%d \n", name, proxy.station.stock)
} else {
fmt.Println("票已售空")
}
}
6.选项模式
Go 语言中,因为不支持给参数设置默认值,为了既能够创建带默认值的实例,又能够创建自定义参数的实例,不少开发者会通过以下两种方法来实现:
package options
import (
"time"
)
type Connection struct {
addr string
cache bool
timeout time.Duration
}
const (
defaultTimeout = 10
defaultCaching = false
)
type options struct {
timeout time.Duration
caching bool
}
// Option overrides behavior of Connect.
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(cache bool) Option {
return optionFunc(func(o *options) {
o.caching = cache
})
}
// Connect creates a connection.
func NewConnect(addr string, opts ...Option) (*Connection, error) {
options := options{
timeout: defaultTimeout,
caching: defaultCaching,
}
for _, o := range opts {
o.apply(&options)
}
return &Connection{
addr: addr,
cache: options.caching,
timeout: options.timeout,
}, nil
}