设计模式总结(golang 版)
几点感受
这是极客时间第 0 期架构师训练营第三周学习总结。
这周主要讲了几种常用设计模式。学完后,有以下几点感受:
设计模式用起来感觉不够直接(我做事喜欢单刀直入),但却是保证代码可扩展、可维护和可协作的基础。所以写代码前还是需要做一些必要的设计。
学习设计模式最好使用像Java或C++这样的面向对象的“原教旨主义”语言。太新的语言,如:Python、Golang,在其语言特性中就包含了一些设计模式的思想,如:Python的装饰器,Go的面相接口编程。
平时工作中用到的一些编程技巧和方法其实都有对应的模式。前人已经为我们总结好了,日用而不自知。
所以,还是要多学习,多思考,多实践。
设计模式总结
简单工厂
// awesomeProject/sorting/sortAlgos.pypackage SorterFactoryimport "fmt"// 定义接口type Sorter interface { Sort([]interface{})}// 冒泡排序type bubbleSorter struct { // 首字母小写,确保外部只能用GetSorter获得实例}//冒泡排序实现Sorter接口func (bbs *bubbleSorter) Sort(sortable []interface{}) { fmt.Print("冒泡排序算法实现。。。")}// 其他排序算法// type insertSorter struct{}// 获得算法实例func GetSorter() Sorter { // 根据配置获得对应的算法实例并返回 sorter := bubbleSorter{} return &sorter}
// main.gopackage mainimport SorterFactory "awesomeProject/sorting"func main() { sorter := SorterFactory.GetSorter() sorter.Sort([]interface{}{1,5,3,7,2})}
简单工厂特点:
优点:
满足开闭原则(OCP)
抽象:调用者和被调用者依赖抽象接口
动态编程:运行时确定被调用的实例类型
缺点:
缺少编译时类型安全
限制了Sorter的实现智能通过“默认构造函数”创建
如果不同实现类需要传递不同参数会变得麻烦
单例模式
懒汉模式
package singletonimport "sync"type singleton1 struct { // 首字母小写,确保外部无法直接实例化}var once sync.Oncevar instance *singleton1func GetInstance() *singleton1 { once.Do(func() { // 确保只执行一次,且执行时加锁 instance = &singleton1{} }) return instance}
饿汉模式
package singletonimport "sync"type singleton2 struct { // 首字母小写,确保外部无法直接实例化 id string}var once sync.Oncevar instance *singleton2func init() { // 加载时执行 once.Do(func() { // 确保只执行一次,且执行时加锁 instance = &singleton2{} })}func GetInstance() *singleton2 { return instance}
适配器模式
该模式适用于,被调用者的接口已经定型的情况下(如:已经在运行的服务),而调用者定义的接口又不兼容被调用者提供的接口,这时可以利用一个适配器类提供接口转换功能。
//定义button和处理button事件的接口package mainimport "fmt"type ButtonServer interface { ButtonPressed(int) // 键被按下后调用}// button 类type Button struct { token int // 按键值 buttonServer ButtonServer // 处理按键事件的对象}// 按键被按下func (b *Button) Pressed() { fmt.Println("key:", b.token, " pressed.") b.buttonServer.ButtonPressed(b.token) // 调用按键事件处理程序}
// 定义dialerpackage mainimport "fmt"type Dailer struct { numbers []int // 存放待拨电话号码}// 按下数字键func (d *Dailer) EnterDigit(token int) { d.numbers = append(d.numbers, token)}// 发送func (d *Dailer) Dail() { fmt.Println("call number:", d.numbers) d.numbers = []int{}}
// 定义适配器package mainimport "fmt"// 数字键适配器type DigitButtonDailerAdapter struct { dailer *Dailer}func (b *DigitButtonDailerAdapter) ButtonPressed(token int) { b.dailer.EnterDigit(token)}// 拨号键适配器type SendButtonDailerAdapter struct { dailer *Dailer}func (b *SendButtonDailerAdapter) ButtonPressed(token int) { b.dailer.Dail()}
package main// 测试func main() { dailer := &Dailer{[]int{}} digitButtonDailerAdapter := &DigitButtonDailerAdapter{dailer} sendButtonDailerAdapter := &SendButtonDailerAdapter{dailer} // 初始化数字键 digitButtons := [10]*Button{} for i := 0; i <= 9; i++ { digitButtons[i] = &Button{i, digitButtonDailerAdapter} } //初始化send键 sendButton := &Button{-99, sendButtonDailerAdapter} // 输入电话号码 for _, n := range []int{1, 3, 8, 3, 4, 5, 6, 7, 8, 9, 0} { digitButtons[n].Pressed() } sendButton.Pressed()}
模版方法
通过“继承”来实现扩展:基类负责算法的轮廓和骨架;子类负责算法的具体实现。
注意:适当使用该模式,多用组合,慎用继承。
Golang不支持严格意义上的继承,对于该模式我认为网上的方法更像是策略模式。
策略模式
系统需要在多种算法中选择一种时,由调用者以参数的形式将算法实现传递给被调用者。
实现一个计算器:
package mainimport "fmt"// 策略抽象type Strategy interface { DoOperation(int, int) int}// 加法实现type OperationAdd struct {}func (add *OperationAdd) DoOperation(num1, num2 int) int { return num1 + num2}// 减法实现type OperationSub struct {}func (sub *OperationSub) DoOperation(num1, num2 int) int { return num1 - num2}// 乘法实现type OperationMulti struct {}func (multi *OperationMulti) DoOperation(num1, num2 int) int { return num1 * num2}// 控制器type Context struct { num1, num2 int strategy Strategy}func (c *Context) ExecuteStrategy() int { return c.strategy.DoOperation(c.num1, c.num2)}// 客户端func main() { context := Context{10,5,new(OperationAdd)} fmt.Println(context.ExecuteStrategy()) context = Context{10,5,new(OperationSub)} fmt.Println(context.ExecuteStrategy()) context = Context{10,5,new(OperationMulti)} fmt.Println(context.ExecuteStrategy())}
组合模式
组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。
package mainimport ( "fmt")// interfacetype Widget interface { Draw()}type BaseWidget struct { WidgetType string text string subWidgets []Widget}// 添加子组件func (w *BaseWidget) Add(widget Widget) { w.subWidgets = append(w.subWidgets, widget)}// 移除子组件func (w *BaseWidget) Remove(idx int) { // todo: 检查idx的有效性 // todo: 空间回收 w.subWidgets[idx] = nil}// drawfunc (w *BaseWidget) Draw() { fmt.Println("draw:", w.WidgetType, w.text) for _, w := range w.subWidgets { if w == nil { continue } w.Draw() }}func main() { winform := BaseWidget{WidgetType: "WinForm", text: "Windown窗口"} picture := BaseWidget{WidgetType: "Picture", text: "logo图片"} buttonLogin := BaseWidget{WidgetType: "Button", text: "登录"} buttonReg := BaseWidget{WidgetType: "Button", text: "注册"} frame := BaseWidget{WidgetType: "Frame", text: "Frame1"} label1 := BaseWidget{WidgetType: "Lable", text: "用户名"} textbox := BaseWidget{WidgetType: "TextBox", text: "文本框"} label2 := BaseWidget{WidgetType: "Lable", text: "用户名"} passwdBox := BaseWidget{WidgetType: "PasswdBox", text: "密码框"} checkBox := BaseWidget{WidgetType: "CheckBox", text: "复选框"} text := BaseWidget{WidgetType: "Text", text: "记住用户名"} linkLable := BaseWidget{WidgetType: "LinkLable", text: "忘记密码"} winform.Add(&picture) winform.Add(&buttonLogin) winform.Add(&buttonReg) winform.Add(&frame) frame.Add(&label1) frame.Add(&textbox) frame.Add(&label2) frame.Add(&passwdBox) frame.Add(&checkBox) frame.Add(&text) frame.Add(&linkLable) winform.Draw()}
装饰模式
装饰模式使用对象组合的方式动态改变或增加对象行为。
package mainimport "fmt"type Shape interface { Draw()}type Circle struct {}func (c *Circle)Draw() { fmt.Println("draw a normal circle")}type RedShapeDecorator struct { shape Shape}func (rd *RedShapeDecorator) Draw() { rd.shape.Draw() fmt.Println("set border color with red")}func main() { circle := Circle{} rc := RedShapeDecorator{&circle} rc.Draw()}
2流程序员
还未添加个人签名 2020.03.18 加入
还未添加个人简介
评论