Go语言设计模式(二)

2021-02-05 06:15

阅读:601

书本实例:
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 的访问进行可控制。


评论


亲,登录后才可以留言!