设计模式(一)

一.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
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值