Dawn's Blogs

分享技术 记录成长

0%

Easy搞定Golang设计模式 (3) 创建型模式之抽象工厂模式 单例模式

抽象工厂模式

工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问题,但由于工厂方法模式中的每个工厂只生产一类产品,可能会导致系统中存在大量的工厂类,势必会增加系统的开销。因此,可以考虑将一些相关的产品组成一个产品族,由同一个工厂来统一生产,这就是抽象工厂模式的基本思想。

产品族和产品等级结构

产品族:具有同一个地区、同一个厂商、同一个开发包、同一个组织模块等,但是具备不同特点或功能的产品集合,称之为是一个产品族。

产品等级结构:具有相同特点或功能,但是来自不同的地区、不同的厂商、不同的开发包、不同的组织模块等的产品集合,称之为是一个产品等级结构。

当程序中的对象可以被划分为产品族和产品等级结构之后,那么抽象工厂方法模式才可以被适用。抽象工厂模式就是一个针对产品族进行生产的。

image-20230418171322007

角色和职责

抽象工厂角色:声明了一组用于创建一族产品的方法,每一个方法对应一种产品。

具体工厂角色:实现了在抽象工厂中声明的创建产品的方法,生成一组具体产品,这些产品构成了一个产品族,每一个产品都位于某个产品等级结构中。

抽象产品角色:工厂所创建对象的父类,描述产品的接口。抽象产品的角色定义了产品等级结构。

具体产品角色:抽象产品的具体实现。

image-20230418171356013

优缺点

优点:

  • 实现了对象创建和使用的分离。

  • 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。

  • 更新产品族时很方便,符合开闭原则

缺点:

  • 更新产品等级结构时违背了开闭原则,会对原有系统进行较大的修改(主要会修改抽象工厂的方法)。

所以,抽象工厂模式适用于产品等级结构稳定,而产品族变化的场景中。

单例模式

单例模式用于保证一个类仅有一个实例,并提供一个访问这个实例的全局访问点

image-20230418173010958

在实现单例模式时,有两个点需要注意:(1)限制调用者直接访问该对象(2)为对象的单例提供一个全局唯一的访问方法。在 Golang 中可以将结构体名称首字母改为小写,来解决(1),而提供一个首字母大写的访问函数,就可以实现(2)了。

单例模式分为饿汉式懒汉式,饿汉式指的是在系统加载时就已经完成了初始化;懒汉式指的是只有当真正用到这个单例的时候才进行初始化。懒汉式在一定程度上节省了内存,但是会有线程安全问题,可以通过普通加锁,或者更高效的双重检验锁来优化。

Golang 有一个更优雅的实现方式,那就是利用 sync.Once,Golang 会保证仅仅只调用一次该方法。

饿汉式

饿汉式在系统加载时就已经完成了初始化。

1
2
3
4
5
6
7
8
type singleton struct{}

// 饿汉式
var instance = &singleton{}

func GetInstance() *singleton {
return instance
}

懒汉式

懒汉式只有当真正用到这个单例的时候才进行初始化,用 sync.Do 来保证初始化时的线程安全。

1
2
3
4
5
6
7
8
9
10
11
12
13
type singleton struct{}

var instance *singleton
type once sync.Once{}

func GetInstance() *singleton {
// 懒汉式,用sync.Do来保证线程安全
once.Do(func() {
instance = &singleton{}
})

return instance
}