Go语言设计模式(二)
2021-02-05 06:15
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 的访问进行可控制。
上一篇:树结构实际应用之 二叉排序树
下一篇:R语言:实现雷达图的绘制