Go语言设计模式(二)

 

建造者模式

将一个复杂的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

以下情况适合使用呢建造者模式
  .当创造复杂对象的算法一个独立于该对象的组成部分以及它们的装配方式时。
  .当构造过程必须允许构造的对象有不同表示时。

  Builder pattern separates the construction of a complex object from its representation so that the same construction process can create different representations.In Go, normally a configuration struct is used to achieve the same behavior, however passing a struct to the builder method fills the code with boilerplate if cfg.Field != nil {...} checks.
书本实例:
package main

type Speed float64

const (
	MPH Speed = 1
	KPH       = 1.60934
)

type Color string

const (
	BlueColor  Color = "blue"
	GreenColor       = "green"
	RedColor         = "red"
)

type Wheels string

const (
	SportsWheels Wheels = "sports"
	SteelWheels         = "steel"
)

type Builder interface {
	Color(Color) Builder
	Wheels(Wheels) Builder
	TopSpeed(Speed) Builder
	Build() Interface
}
type Interface interface {
	Drive() error
	Stop() error
}

// 使用 func main() { // 必须先实现car的各种方法的,并实例化为car assembly := car.NewBuilder().Paint(car.RedColor) familyCar := assembly.Wheels(car.SportsWheels).TopSpeed(50 * car.MPH).Build() familyCar.Drive() sportsCar := assembly.Wheels(car.SteelWheels).TopSpeed(150 * car.MPH).Build() sportsCar.Drive() }  

简单实例:

package main

import (
    "fmt"
)

type Glasses struct {
    Price int64
    From  string
}

type Builder interface {
    BuildPrice(int64)
    BuildForm()
    GetGlasses() Glasses
}

type ShenZhenBuilder struct {
    glasses Glasses
}

type ShanWeiBuilder struct {
    glasses Glasses
}

func (pS *ShenZhenBuilder) BuildPrice(iP int64) {
    pS.glasses.Price = iP * 10
}

func (pS *ShenZhenBuilder) BuildForm() {
    pS.glasses.From = "shenzhen"
}

func (pS *ShenZhenBuilder) GetGlasses() Glasses {
    return pS.glasses
}

func (pS *ShanWeiBuilder) BuildPrice(iP int64) {
    pS.glasses.Price = iP * 2
}

func (pS *ShanWeiBuilder) BuildForm() {
    pS.glasses.From = "shanwei"
}

func (pS *ShanWeiBuilder) GetGlasses() Glasses {
    return pS.glasses
}

type LeshiGlasses struct {
    First_cost int64
}

func (L *LeshiGlasses) GetGlasses(b Builder) Glasses {
    b.BuildPrice(L.First_cost)
    b.BuildForm()
    return b.GetGlasses()
}

func main() {

    leshi := &LeshiGlasses{First_cost: 100}
    var glassesbuilder Builder
    glassesbuilder = &ShanWeiBuilder{}
    glasses := leshi.GetGlasses(glassesbuilder)
    fmt.Println("glasses's price is: ", glasses.Price, " glasses from :", glasses.From)
    glassesbuilder = &ShenZhenBuilder{}
    glasses = leshi.GetGlasses(glassesbuilder)
    fmt.Println("glasses's price is: ", glasses.Price, " glasses from :", glasses.From)

    return
}

/*
glasses's price is:  200  glasses from : shanwei
glasses's price is:  1000  glasses from : shenzhen*/ 

  在同一个类型的Director(乐视眼镜下),有不同的构造方法,分别是深圳眼镜和汕尾眼镜。如果要在广州增加一个广州眼镜。只需要增加一个广州眼镜,并实现广州眼镜的时间。对应乐视眼镜构造广州眼镜的方式还是一致的,因为其成本是一致的。如果要增加明凯眼镜,则只需要增加一个明凯眼镜的Director即可。将对眼镜创建的过程,从直接创建,分解到Director和Builder(框架),使得构造代码和表示代码分开。在Builder的具体实现结构可以更加精细的构造每个环节。

原型模式

用原型实例指定创造对象的种类,并且通过拷贝这些原型创建新的对象。可以理解为可以基于一个对象新创建的对象继承原有属性

package main
import (
    "fmt"
)

type Role interface {
    Clone() Role
    SetHeadColor(string)
    SetEyesColor(string)
    SetTall(int64)
    Show()
}

type RoleChinese struct {
    HeadColor string
    EyesColor string
    Tall      int64
}

func (pR *RoleChinese) Clone() Role {
    var pChinese = &RoleChinese{HeadColor: pR.HeadColor, EyesColor: pR.EyesColor, Tall: pR.Tall}
    return pChinese
}

func (pR *RoleChinese) SetHeadColor(color string) {
    pR.HeadColor = color
}

func (pR *RoleChinese) SetEyesColor(color string) {
    pR.EyesColor = color
}

func (pR *RoleChinese) SetTall(tall int64) {
    pR.Tall = tall
}

func (pR *RoleChinese) Show() {
    fmt.Println("Role's headcolor is:", pR.HeadColor, " EyesColor is:", pR.EyesColor, " tall is:", pR.Tall)
}
func main() {
    var role Role
    role = &RoleChinese{HeadColor: "black", EyesColor: "black", Tall: 170}
    role.Show()
    ThisWriter := role.Clone()
    ThisWriter.SetTall(180)
    ThisWriter.Show()
    return
}

/*
Role's headcolor is: black  EyesColor is: black  tall is: 170
Role's headcolor is: black  EyesColor is: black  tall is: 180*/

从例子中可以看到如果重新去创建ThisWriter这个对象,就会像新建role一样,这里类型相对简单,在实际开发中可能会是个比较复杂的类型。但是role和ThisWriter其他都一致,只有Tall不一致,如果重新创建会比较繁琐。用工厂类的话也会不是很合适,因为role和ThisWriter只有Tall属性不一致。如果再增加几个不同小改动的Role,使用工厂类会引入大量的类。所以使用原型模式最为合适。

 

适配器模式

将一个类型的接口转换成客户希望的另外一个接口,使原本由于接口不兼容而不能一起工作的类可以一起工作。可以对原有接口进行扩展

package main
import (
    "fmt"
)

type OldInterface interface {
    InsertToDatabase(Data interface{}) (bool, error)
}

type AddCustomInfoToMysql struct {
    DbName string
}

func (pA *AddCustomInfoToMysql) InsertToDatabase(info interface{}) (bool, error) {
    switch info.(type) {
    case string:
        fmt.Println("add ", info.(string), " to ", pA.DbName, " successful!")
    }
    return true, nil
}

type NewInterface interface {
    SaveData(Data interface{}) (bool, error)
}

type Adapter struct {
    OldInterface
}

func (pA *Adapter) SaveData(Data interface{}) (bool, error) {
    fmt.Println("In Adapter")
    return pA.InsertToDatabase(Data)
}

func main() {

    var iNew NewInterface
    iNew = &Adapter{OldInterface: &AddCustomInfoToMysql{DbName: "mysql"}}
    iNew.SaveData("helloworld")
    return
}

  从实现例子可以看出,老接口方法为InsertToDatabase,新接口方法为SaveData。两者具有一点的相似性。当系统不想保留接口的时候,就可以用适配器来修饰。

 

代理模式

代理模式为其他对象提供一种代理以控制对一个对象的访问。是一种对象结构型模式。也就是说可以更加细粒度的控制函数的调用

代码实现:

package main

import (
    "fmt"
)

type Handler interface {
    HandleData(string) (interface{}, error)
}

type DBHandler struct {
    DBname string
}

func (pD *DBHandler) HandleData(data string) (interface{}, error) {
    fmt.Println("Get Db data by query sql :", data)
    return nil, nil
}

type AppHandler struct {
    Handler *DBHandler 
}

func (pA *AppHandler) HandleData(data string) (interface{}, error) {
    if true { //Get Data from redis ok
        fmt.Println("Get Data from redis")
    } else {
        pA.Handler.HandleData(data)
        //store ret data data to redis 
    }
    return nil, nil
}

func main() {

    var iHandler Handler
    iHandler = &AppHandler{Handler: &DBHandler{DBname: "mysql"}}
    iHandler.HandleData("username")
    return
}

  从实例可以看出,在AppHandler中增加了优化查询逻辑,当redis中无对应数据时才到mysql中查询数据。这就对DBHandler 的访问进行可控制。

posted @ 2020-04-27 23:52  独角兕大王  阅读(200)  评论(0编辑  收藏  举报