创建型模式对类的实例化过程进行了抽象,能够将对象的创建与对象的使用过程分离。
对于系统中的某些类来说,只有一个实例很重要:
如何保证一个类只有一个实例并且这个实例易于被访问呢?
单例模式(Singleton Pattern):确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。
单例模式的要点有三个:
单例模式是一种对象创建型模式。单例模式又名单件模式或单态模式。
单例模式只包含一个角色:Singleton(单例)
sync.Once
是让函数方法只被调用执行一次的实现,最常应用于单例模式,例如:
这样就可以满足单例模式的要求。
package singleton
import "sync"
//Singleton 是单例模式类
type Singleton struct{}
var (
singleton *Singleton
once sync.Once
)
//GetInstance 用于获取单例模式对象
func GetInstance() *Singleton {
once.Do(func() {
singleton = &Singleton{}
})
return singleton
}
type Once struct {
// done indicates whether the action has been performed.
// It is first in the struct because it is used in the hot path.
// The hot path is inlined at every call site.
// Placing done first allows more compact instructions on some architectures (amd64/x86),
// and fewer instructions (to calculate offset) on other architectures.
done uint32 // 调用标识符,Once对象初始化时,done值默认为0,Do方法被调用后变为1
m Mutex // 初始化竞态控制,在第一次调用Once.Do()方法时,会通过m加锁,
// 保证在第一个Do()方法中的参数f()函数还未执行完毕时,
// 其他此时调用Do()方法会被阻塞(不返回也不执行)
}
func (o *Once) Do(f func()) {
// Do()方法的入参是一个无参数输入与返回的函数
// Note: Here is an incorrect implementation of Do:
//
// if atomic.CompareAndSwapUint32(&o.done, 0, 1) {
// f()
// }
//
// Do guarantees that when it returns, f has finished.
// This implementation would not implement that guarantee:
// given two simultaneous calls, the winner of the cas would
// call f, and the second would return immediately, without
// waiting for the first's call to f to complete.
// This is why the slow path falls back to a mutex, and why
// the atomic.StoreUint32 must be delayed until after f returns.
// 下面这个if中原子读取o.done的值并判断,是为了保证其他调用会先阻塞,而不是直接退出
// 如果其他调用直接退出了,但是单例还没有初始化,就会有异常了
if atomic.LoadUint32(&o.done) == 0 { // 当o.done值为0时,执行doSlow()方法
// Outlined slow-path to allow inlining of the fast-path.
o.doSlow(f)
}
// 当o.done值为1则退出Do()方法
}
func (o *Once) doSlow(f func()) {
o.m.Lock() // 加锁
defer o.m.Unlock() // 方法退出时释放锁
if o.done == 0 { // 再次检查o.done值
defer atomic.StoreUint32(&o.done, 1) // 原子操作将o.done值置为1
f() // 执行传入的函数
}
}
注意:由于
o.m.Lock()
处的代码限定,once.Do()
内部调用Do()
方法时,会造成死锁的发生。
简单工厂模式(Simple Factory Pattern):又称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
简单工厂模式包含如下角色:
样例代码来源。
工厂角色:
package simplefactory
//NewAPI return Api instance by type
func NewAPI(t int) API {
if t == 1 {
return &hiAPI{}
} else if t == 2 {
return &helloAPI{}
}
return nil
}
抽象产品角色:
package simplefactory
//API is interface
type API interface {
Say(name string) string
}
具体产品角色:
package simplefactory
import "fmt"
//hiAPI is one of API implement
type hiAPI struct{}
//Say hi to name
func (*hiAPI) Say(name string) string {
return fmt.Sprintf("Hi, %s", name)
}
//HelloAPI is another API implement
type helloAPI struct{}
//Say hello to name
func (*helloAPI) Say(name string) string {
return fmt.Sprintf("Hello, %s", name)
}
go 语言没有构造函数一说,所以一般会定义NewXXX函数来初始化相关类。 NewXXX 函数返回接口时就是简单工厂模式,也就是说Golang的一般推荐做法就是简单工厂。
在这个simplefactory包中只有API接口和NewAPI函数为包外可见,封装了实现细节。
简单工厂模式又称为静态工厂方法模式,它属于类创建型模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
简单工厂模式包含三个角色:
简单工厂模式的要点在于:当你需要什么,只需要传入一个正确的参数,就可以获取你所需要的对象,而无须知道其创建细节。
简单工厂模式适用情况包括:工厂类负责创建的对象比较少;客户端只知道传入工厂类的参数,对于如何创建对象不关心。
更详细的介绍看图解设计模式。
工厂方法模式(Factory Method Pattern)又称为工厂模式,也叫虚拟构造器(Virtual Constructor)模式或者多态工厂(Polymorphic Factory)模式,它属于类创建型模式。在工厂方法模式中,工厂父类负责定义创建产品对象的公共接口,而工厂子类则负责生成具体的产品对象,这样做的目的是将产品类的实例化操作延迟到工厂子类中完成,即通过工厂子类来确定究竟应该实例化哪一个具体产品类。
工厂方法模式包含如下角色:
样例代码来源。
抽象产品:
package factorymethod
//Operator 是被封装的实际类接口
type Operator interface {
SetA(int)
SetB(int)
Result() int
}
具体产品:
package factoryMethod
type OperatorBase struct {
a, b int
}
func (o *OperatorBase) SetA(i int) {
o.a = i
}
func (o *OperatorBase) SetB(i int) {
o.b = i
}
//PlusOperator Operator 的实际加法实现
type PlusOperator struct {
*OperatorBase
}
//Result 获取结果
func (p PlusOperator) Result() int {
return p.a + p.b
}
//MinusOperator Operator 的实际减法实现
type MinusOperator struct {
*OperatorBase
}
//Result 获取结果
func (m MinusOperator) Result() int {
return m.a - m.b
}
抽象工厂:
package factoryMethod
//OperatorFactory 是工厂接口
type OperatorFactory interface {
Create() Operator
}
具体工厂:
package factoryMethod
//PlusOperatorFactory 是 PlusOperator 的工厂类
type PlusOperatorFactory struct{}
func (PlusOperatorFactory) Create() Operator {
return &PlusOperator{
OperatorBase: &OperatorBase{},
}
}
//MinusOperatorFactory 是 MinusOperator 的工厂类
type MinusOperatorFactory struct{}
func (MinusOperatorFactory) Create() Operator {
return &MinusOperator{
OperatorBase: &OperatorBase{},
}
}
工厂方法模式使用子类的方式延迟生成对象到子类中实现。
Go中不存在继承 所以使用匿名组合来实现
工厂方法模式又称为工厂模式,它属于类创建型模式。在工厂方法模式中,工厂父类负责定义创建产品对象的公共接口,而工厂子类则负责生成具体的产品对象,这样做的目的是将产品类的实例化操作延迟到工厂子类中完成,即通过工厂子类来确定究竟应该实例化哪一个具体产品类。
工厂方法模式包含四个角色:
工厂方法模式是简单工厂模式的进一步抽象和推广。由于使用了面向对象的多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。在工厂方法模式中,核心的工厂类不再负责所有产品的创建,而是将具体创建工作交给子类去做。这个核心类仅仅负责给出具体工厂必须实现的接口,而不负责哪一个产品类被实例化这种细节,这使得工厂方法模式可以允许系统在不修改工厂角色的情况下引进新产品。
工厂方法模式适用情况包括:
更详细的介绍看图解设计模式。
抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,属于对象创建型模式。
抽象工厂模式包含如下角色:
样例代码来源。
抽象工厂:
package abstractFactory
// DAOFactory DAO抽象模式工厂接口
type DAOFactory interface {
CreateOrderMainDAO() OrderMainDAO
CreateOrderDetailDAO() OrderDetailDAO
}
具体工厂:
package abstractFactory
type RDBDAOFactory struct {
}
func (R *RDBDAOFactory) CreateOrderMainDAO() OrderMainDAO {
return &RDBMainDAO{}
}
func (R *RDBDAOFactory) CreateOrderDetailDAO() OrderDetailDAO {
return &RDBDetailDAO{}
}
type XMLDAOFactory struct {
}
func (X *XMLDAOFactory) CreateOrderMainDAO() OrderMainDAO {
return &XMLMainDAO{}
}
func (X *XMLDAOFactory) CreateOrderDetailDAO() OrderDetailDAO {
return &XMLDetailDAO{}
}
抽象产品:
package abstractFactory
// OrderMainDAO 为订单主记录
type OrderMainDAO interface {
SaveOrderMain()
}
// OrderDetailDAO 为订单详情纪录
type OrderDetailDAO interface {
SaveOrderDetail()
}
具体产品:
package abstractFactory
import "fmt"
// RDBMainDAP 为关系型数据库的OrderMainDAO实现
type RDBMainDAO struct {
}
// SaveOrderMain ...
func (R *RDBMainDAO) SaveOrderMain() {
fmt.Print("rdb main save\n")
}
// RDBDetailDAO 为关系型数据库的OrderDetailDAO实现
type RDBDetailDAO struct {
}
// SaveOrderDetail ...
func (R *RDBDetailDAO) SaveOrderDetail() {
fmt.Print("rdb detail save\n")
}
// XMLMainDAO XML存储
type XMLMainDAO struct{}
// SaveOrderMain ...
func (*XMLMainDAO) SaveOrderMain() {
fmt.Print("xml main save\n")
}
// XMLDetailDAO XML存储
type XMLDetailDAO struct{}
// SaveOrderDetail ...
func (*XMLDetailDAO) SaveOrderDetail() {
fmt.Print("xml detail save")
}
抽象工厂模式用于生成产品族的工厂,所生成的对象是有关联的。
如果抽象工厂退化成生成的对象无关联则成为工厂函数模式。
比如本例子中使用RDB和XML存储订单信息,抽象工厂分别能生成相关的主订单信息和订单详情信息。 如果业务逻辑中需要替换使用的时候只需要改动工厂函数相关的类就能替换使用不同的存储方式了。
抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,属于对象创建型模式。
抽象工厂模式包含四个角色:
抽象工厂模式是所有形式的工厂模式中最为抽象和最具一般性的一种形态。抽象工厂模式与工厂方法模式最大的区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则需要面对多个产品等级结构。
抽象工厂模式适用情况包括:
更详细的介绍看图解设计模式。