一.builder pattern
一.文档
https://github.com/tmrts/go-patterns/blob/master/creational/builder.md
https://golangvedu.wordpress.com/2017/02/09/golang-builder-pattern-creational/
二.个人理解
builder模式,翻译为建造模式,核心思想是类的实例创建、某个事物的创造提供不同的builder类代为执行。在汽车生产中,存在跑车、卡车、轿车等类型,厂房中的流水线可以抽象成一样的流程(生产零件、组装、喷漆),厂房中生产按照这些抽象的既定流程走即可完成生产,而生产出来什么类型的汽车则由具体的builder类(实现生产零件、组装、喷漆的接口)实现。
应用场景:抽象创建流程,具体的创建方式可扩展,接口可以避免修改,符合开闭原则的思想。
三.角色分类
builder 接口类,提供抽象的接口;类比为抽象出来的流程(生产零件、组装、喷漆)
concretebuilder 具体实现方法类,实现builder的各项接口;类比跑车生产线、卡车生产线等
director 导演、监工。调用builder接口实现生产,不同的builder产出不同的产品;
// builder模式样例
// 模拟现实中汽车流水线
package main
import (
"fmt"
)
// 汽车结构
type Car struct {
// 引擎
Engine string
// 底盘
Chassis string
// 悬挂
Suspension string
// 颜色
Color string
}
// builder抽象接口
type CarBuilder interface {
// 生产零件
MakeParts(car *Car) error
// 组装
Assemble(car *Car) error
// 喷漆
Paint(car *Car) error
}
// 保时捷builder实例
type PorscheBuilder struct {}
// 生产保时捷三大件
func (p PorscheBuilder) MakeParts(car *Car) error {
car.Engine = "V6"
car.Chassis = "PDCC"
car.Suspension = "PASM"
return nil
}
// 组装保时捷
func (p PorscheBuilder) Assemble(car *Car) error {
fmt.Println("PorscheBuilder| Assemble a porsche car success.")
return nil
}
// 喷漆保时捷
func (p PorscheBuilder) Paint(car *Car) error {
car.Color = "red"
return nil
}
// 大众builder实例
type VolkswagenBuilder struct {}
// 生产大众三大件
func (v VolkswagenBuilder) MakeParts(car *Car) error {
car.Engine = "EA111"
car.Chassis = "DCC"
car.Suspension = "MacPhersan"
return nil
}
// 组装大众
func (v VolkswagenBuilder) Assemble(car *Car) error {
fmt.Println("VolkswagenBuilder| Assemble a volkswagen car success.")
return nil
}
// 喷漆大众
func (v VolkswagenBuilder) Paint(car *Car) error {
car.Color = "black"
return nil
}
// director
type Direcotr struct {
Builder CarBuilder
}
// direcotr的构建方法
func (d *Direcotr) ChoseBuilder(builder CarBuilder) {
d.Builder = builder
}
// direcotr的构建方法
func (d *Direcotr) Build() {
car := new(Car)
if err := d.Builder.MakeParts(car); err != nil {
fmt.Printf("Direcotr| make parts failed[%s].", err.Error())
}
if err := d.Builder.Assemble(car); err != nil {
fmt.Printf("Direcotr| Assemble failed[%s].", err.Error())
}
if err := d.Builder.Paint(car); err != nil {
fmt.Printf("Direcotr| Paint failed[%s].", err.Error())
}
fmt.Printf("Director| build car success, engine[%s] chassis[%s] suspension[%s] color[%s].\n",
car.Engine, car.Chassis, car.Suspension, car.Color)
}
func main() {
// 创建builder实例
porscheBuilder := PorscheBuilder{}
volkswagenBuilder := VolkswagenBuilder{}
// 构造保时捷
direcotr := Direcotr{}
direcotr.ChoseBuilder(porscheBuilder)
direcotr.Build()
// 构造大众
direcotr.ChoseBuilder(volkswagenBuilder)
direcotr.Build()
}
二.factory、factory method、abstract factory
一.文档
https://www.cnblogs.com/toutou/p/4899388.html
https://www.zhihu.com/question/20367734
二.个人理解
工厂模式、工厂方法、抽象工厂三种设计模式都是用于可重复地、批量地创建对象,可以类比为现实生活中的工厂,输入为客户所要求的产品参数,输出即为真实对象。此模式屏蔽了生产的具体过程,类之间进行解耦,例如程序猿工作使用的键盘为工厂所生产,各个程序员对键盘的类型有不同要求,可使用工厂相关模式进行生产,程序猿类只关心工厂的生产接口而不关心工厂的具体生产过程,当工厂中的生产过程改变(例如采购材料的方式变了)也不影响程序猿的使用(接口未变)。
应用场景:用于可重复创建对象。
三.角色分类
factory(简单工厂)
简单工厂只提供一个工厂,该工厂提供多种产品。根据用户输入生产对应不同类型的产品。不符合开闭原则,当有新产品类型需要增加时必须修改已有代码,增加分支流程。
工厂中有生产键盘的方法,用户输入类型(机械键盘、薄膜键盘等),工厂返回对应的实例
抽象产品类:产品接口
具体产品类:具体的产品类型。
工厂类:提供生产方法
factory method(工厂方法) 工厂方法是对简单工厂的一种抽象,每个产品都对应一个工厂,生产哪种产品就调用哪个产品对应的工厂。工厂类之间相互独立,互不干扰,可通过扩展增加不同的工厂,生产不同的产品。 多个工厂,有机械键盘工厂、薄膜键盘工厂,用户想要哪种产品就访问哪个工厂
抽象产品类:产品接口
具体产品类:具体的产品类型。
工厂接口类:提供产品生产接口
具体工厂类:实现生产接口,每个工厂类对应一种产品
abstract factory(抽象工厂) 抽象工厂中是对工厂方法的进一步抽象,提供一个抽象组合工厂类接口,该类中实现对多种产品的组合生成。 多个工厂,有机械键盘工厂、薄膜键盘工厂,还有相关的机械键盘包工厂、薄膜键盘包工厂,同时提供薄膜键盘套件工厂,机械键盘套件工厂。用户访问套件工厂生成对应的套件(例如薄膜键盘+薄膜键盘包)
抽象产品类:产品接口
具体产品类:具体的产品类型。
工厂接口类:提供产品生产接口
具体工厂类:实现生产接口,每个工厂类对应一种产品
组合工厂类:该工厂生成一系列相关的产品
package main
import (
"fmt"
"errors"
)
// 键盘类型
const (
// 机械键盘
mechanicalType = 1
// 薄膜键盘
membraneType = 2
)
// 键盘产品抽象接口
type keyboard interface {
Strike(string)
}
// 机械键盘产品
type mechanicalKeyboard struct {}
// 机械键盘敲击接口
func (mk *mechanicalKeyboard) Strike(letter string) {
fmt.Printf("mechanicalKeyboard| strike a letter[%s].\n", letter)
}
// 薄膜键盘产品
type membraneKeyboard struct {}
// 薄膜键盘敲击接口
func (mk *membraneKeyboard) Strike(letter string) {
fmt.Printf("membraneKeyboard| strike a letter[%s].\n", letter)
}
// 键盘工厂
type keyboardFactory struct{}
// 生产键盘接口
func (kf *keyboardFactory) Create(keyboardType int) (keyboard, error) {
switch keyboardType {
case mechanicalType:
return new(mechanicalKeyboard), nil
case membraneType:
return new(membraneKeyboard), nil
default:
return nil, errors.New("no support keyboard type")
}
}
func main() {
factory := keyboardFactory{}
// 生产机械键盘
keyboardA, err := factory.Create(mechanicalType)
if err != nil {
fmt.Printf("Main| create mechanicalType keyboard failed[%s].", err.Error())
} else {
keyboardA.Strike("hello")
}
// 生产薄膜键盘
keyboardB, err := factory.Create(membraneType)
if err != nil {
fmt.Printf("Main| create membraneType keyboard failed[%s].", err.Error())
} else {
keyboardB.Strike("world")
}
return
}
package main
import (
"fmt"
)
// 键盘类型
const (
// 机械键盘
mechanicalType = 1
// 薄膜键盘
membraneType = 2
)
// 键盘产品抽象接口
type keyboard interface {
Strike(string)
}
// 机械键盘产品
type mechanicalKeyboard struct {}
// 机械键盘敲击接口
func (mk *mechanicalKeyboard) Strike(letter string) {
fmt.Printf("mechanicalKeyboard| strike a letter[%s].\n", letter)
}
// 薄膜键盘产品
type membraneKeyboard struct {}
// 薄膜键盘敲击接口
func (mk *membraneKeyboard) Strike(letter string) {
fmt.Printf("membraneKeyboard| strike a letter[%s].\n", letter)
}
type keyboardFactory interface {
Create() (keyboard, error)
}
// 机械键盘工厂
type mechanicalKeyboardFactory struct{}
// 生产机械键盘接口
func (mkf *mechanicalKeyboardFactory) Create() (keyboard, error) {
return new(mechanicalKeyboard), nil
}
// 薄膜键盘工厂
type membraneKeyboardFactory struct{}
// 生产机械键盘接口
func (mkf *membraneKeyboardFactory) Create() (keyboard, error) {
return new(membraneKeyboard), nil
}
func main() {
factoryA := mechanicalKeyboardFactory{}
factoryB := membraneKeyboardFactory{}
// 生产机械键盘
keyboardA, err := factoryA.Create()
if err != nil {
fmt.Printf("Main| create mechanicalType keyboard failed[%s].", err.Error())
} else {
keyboardA.Strike("hello")
}
// 生产薄膜键盘
keyboardB, err := factoryB.Create()
if err != nil {
fmt.Printf("Main| create membraneType keyboard failed[%s].", err.Error())
} else {
keyboardB.Strike("world")
}
return
}
package main
import (
"fmt"
)
// 键盘类型
const (
// 机械套件
mechanicalType = 1
// 薄膜键盘
membraneType = 2
)
// 键盘包产品抽象接口
type KeyboardPacket interface {
Pack()
}
// 机械键盘包
type mechanicalPacket struct {}
// 机械键盘打包
func (mp *mechanicalPacket) Pack() {
fmt.Printf("mechanicalPacket| pack keyboard.\n")
}
// 薄膜键盘包
type membranePacket struct {}
// 机械键盘打包
func (mp *membranePacket) Pack() {
fmt.Printf("membranePacket| pack keyboard.\n")
}
// 键盘产品抽象接口
type keyboard interface {
Strike(string)
}
// 机械键盘产品
type mechanicalKeyboard struct {}
// 机械键盘敲击接口
func (mk *mechanicalKeyboard) Strike(letter string) {
fmt.Printf("mechanicalKeyboard| strike a letter[%s].\n", letter)
}
// 薄膜键盘产品
type membraneKeyboard struct {}
// 薄膜键盘敲击接口
func (mk *membraneKeyboard) Strike(letter string) {
fmt.Printf("membraneKeyboard| strike a letter[%s].\n", letter)
}
type keyboardFactory interface {
CreateKeyboard() (keyboard, error)
CreateKeyboardPacket() (KeyboardPacket, error)
}
// 机械键盘工厂
type mechanicalKeyboardFactory struct{}
// 生产机械键盘接口
func (mkf *mechanicalKeyboardFactory) CreateKeyboard() (keyboard, error) {
return new(mechanicalKeyboard), nil
}
// 生产机械键盘接口
func (mkf *mechanicalKeyboardFactory) CreateKeyboardPacket() (KeyboardPacket, error) {
return new(mechanicalPacket), nil
}
// 薄膜键盘工厂
type membraneKeyboardFactory struct{}
// 生产机械键盘接口
func (mkf *membraneKeyboardFactory) CreateKeyboard() (keyboard, error) {
return new(membraneKeyboard), nil
}
// 生产机械键盘包接口
func (mkf *membraneKeyboardFactory) CreateKeyboardPacket() (KeyboardPacket, error) {
return new(membranePacket), nil
}
func main() {
factoryA := mechanicalKeyboardFactory{}
//factoryB := membraneKeyboardFactory{}
// 生产机械键盘
keyboardA, err := factoryA.CreateKeyboard()
if err != nil {
fmt.Printf("Main| create mechanicalType keyboard failed[%s].\n", err.Error())
} else {
keyboardA.Strike("hello")
}
keyboardPacketA, err := factoryA.CreateKeyboardPacket()
if err != nil {
fmt.Printf("Main| create mechanicalType keyboard packet failed[%s].\n", err.Error())
} else {
keyboardPacketA.Pack()
}
return
}
三.object pool
一.文档
https://github.com/theodesp/go-object-pool
https://golang.org/pkg/sync/
二.个人理解
对象池用于提供对象获取接口,池子中存放一组对象,当需要对象时直接从池子中取出即可,当池子中没有对象可供使用时池子自动new出需要的对象并返回。
该模式常用于连接池,请求结构体构造等创造对象比较耗时的情况。
三.角色
pool 对象池,提供get方法获取object
object 真实对象
四.实例
golang sync包提供pool机制,但sync.Pool只解决对象复用的问题,pool中的对象生命周期是两次gc之间,gc后pool中的对象会被回收,使用方不能控制对象的生命周期,所以不适合用在连接池等场景。
此处实例为使用sync中pool实现,如果需要控制对象声明周期等等需求可以通过自定义来实现pool。
package main
import (
"fmt"
"sync"
)
// 内存池中存放对象
type object struct {
name string
}
func (o *object) Display() {
fmt.Printf("object| name[%s]\n", o.name)
}
func NewObject() interface{} {
obj := object {
name : "object created from pool",
}
return obj
}
func main() {
var objPool = sync.Pool {
New : NewObject,
}
obj := objPool.Get().(object)
obj.Display()
return
}