手撸golang 行为型设计模式 策略模式

缘起

最近温习设计模式
拜读谭勇德的<<设计模式就该这样学>>
本系列笔记拟采纳golang练习之

策略模式

策略模式(Strategy Pattern)又叫作政策模式(Policy Pattern),它将定义的算法家族别离封装起来,让它们之间能够相互替换,从而让算法的变动不会影响到应用算法的用户,属于行为型设计模式。(摘自 谭勇德 <<设计模式就该这样学>>)

场景

  • 某学员问题管理系统, 须要对学员问题进行排序
  • 码农王二狗依据<<我的第一本算法书>>里的形容, 应用冒泡排序算法实现了问题排序功能
  • Leader审查代码时, 认为王二狗的实现尽管实现了性能, 但不够sexy, 要求改良
  • 于是王二狗持续翻查算法书, 又加上了抉择排序和疾速排序算法.
  • 为兼容性和可扩展性思考, 王二狗依据策略模式, 把排序算法都形象成对立接口, 等Leader说哪个好, 就用那个.

设计

  • ISortPolicy: 排序算法接口
  • tBubbleSortPolicy: 冒泡排序算法, 实现ISortPolicy接口
  • tSelectSortPolicy: 抉择排序算法, 实现ISortPolicy接口
  • tQuickSortPolicy: 疾速排序算法, 实现ISortPolicy接口. 外部顺便实现了一个LIFO栈 - tIntStack.

单元测试

policy_pattern_test.go, 生成若干随机整数, 而后别离应用冒泡, 抉择, 疾速排序算法进行排序

package behavioral_patternsimport (    plc "learning/gooop/behavioral_patterns/policy"    "math/rand"    "testing"    "time")func Test_PolicyPattern(t *testing.T) {    size := 20    data := make([]int, size)    r := rand.New(rand.NewSource(time.Now().Unix()))    for i, _ := range data {        data[i] = r.Intn(100)    }    t.Logf("UnsortedData \t= %v", data)    fnMakeCopy := func() []int{        copies := make([]int, size)        for i,v := range data {            copies[i] = v        }        return copies    }    fnTestPolicy := func(policy plc.ISortPolicy) {        sorted := policy.Sort(fnMakeCopy())        t.Logf("%s \t= %v", policy.Name(), sorted)    }    fnTestPolicy(plc.NewBubbleSortPolicy())    fnTestPolicy(plc.NewSelectSortPolicy())    fnTestPolicy(plc.NewQuickSortPolicy())}

测试输入

$ go test -v policy_pattern_test.go === RUN   Test_PolicyPattern    policy_pattern_test.go:17: UnsortedData     = [19 17 28 36 80 84 70 7 80 68 2 96 94 26 22 31 80 49 49 69]    policy_pattern_test.go:29: BubbleSort       = [2 7 17 19 22 26 28 31 36 49 49 68 69 70 80 80 80 84 94 96]    policy_pattern_test.go:29: SelectSort       = [2 7 17 19 22 26 28 31 36 49 49 68 69 70 80 80 80 84 94 96]    policy_pattern_test.go:29: QuickSort        = [2 7 17 19 22 26 28 31 36 49 49 68 69 70 80 80 80 84 94 96]--- PASS: Test_PolicyPattern (0.00s)PASSok      command-line-arguments  0.002s

ISortPolicy.go

排序算法接口

package policytype ISortPolicy interface {    Name() string    Sort(data []int) []int}

tBubbleSortPolicy.go

冒泡排序算法, 实现ISortPolicy接口

package policy// 冒泡排序type tBubbleSortPolicy struct {}func NewBubbleSortPolicy() ISortPolicy {    return &tBubbleSortPolicy{}}func (self *tBubbleSortPolicy) Name() string {    return "BubbleSort"}func (self *tBubbleSortPolicy) Sort(data []int) []int {    if data == nil {        return nil    }    size := len(data)    if size <= 1 {        return data    }    for {        i := size - 1        changed := false        for {            if i <= 0 {                break            }            j := i - 1            if data[j] > data[i] {                data[i],data[j] = data[j],data[i]                changed = true            }            i--        }        if !changed {            break        }    }    return data}

tSelectSortPolicy.go

抉择排序算法, 实现ISortPolicy接口

package policy// 抉择排序type tSelectSortPolicy struct {}func NewSelectSortPolicy() ISortPolicy {    return &tSelectSortPolicy{}}func (self *tSelectSortPolicy) Name() string {    return "SelectSort"}func (self *tSelectSortPolicy) Sort(data []int) []int {    if data == nil {        return nil    }    size := len(data)    if size <= 1 {        return data    }    i := 0    for {        if i >= size - 1 {            break        }        p, m := self.min(data, i + 1, size - 1)        if m < data[i] {            data[p], data[i] = data[i], data[p]        }        i++    }    return data}func (self *tSelectSortPolicy) min(data []int, from int, to int) (p int, v int) {    i := from    p = from    v = data[from]    if to <= from {        return p, v    }    for {        i++        if i > to {            break        }        if data[i] < v {            p = i            v = data[i]        }    }    return p, v}

tQuickSortPolicy.go

疾速排序算法, 实现ISortPolicy接口. 外部顺便实现了一个LIFO栈.

package policyimport "errors"// 疾速排序type tQuickSortPolicy struct {    mLeftStack *tIntStack    mRightStack *tIntStack}func NewQuickSortPolicy() ISortPolicy {    return &tQuickSortPolicy{        newIntStack(),newIntStack(),    }}// LIFO栈type tIntStack struct {    tail *tIntNode    size int}type tIntNode struct {    Value int    Prev *tIntNode}func newIntNode(value int) *tIntNode {    return &tIntNode {        value, nil,    }}func newIntStack() *tIntStack {    return &tIntStack{        nil,        0,    }}func (self *tIntStack) Push(i int) {    node := newIntNode(i)    node.Prev = self.tail    self.tail = node    self.size++}func (self *tIntStack) Pop() (error,int) {    if self.size > 0 {        self.size--        node := self.tail        self.tail = self.tail.Prev        return nil, node.Value    } else {        return errors.New("empty stack"), 0    }}func (self *tIntStack) Size() int {    return self.size}func (self *tQuickSortPolicy) Name() string {    return "QuickSort"}func (self *tQuickSortPolicy) Sort(data []int) []int {    self.qsort(data, 0, len(data) - 1)    return data}func (self *tQuickSortPolicy) qsort(data []int, from int, to int)  {    if to <= from {        return    }    // only two    if to == from + 1 {        if data[to] < data[from] {            data[from], data[to] = data[to], data[from]        }        return    }    // get pivot    iPivot := (from + to) / 2    vPivot := data[iPivot]    // split left and right    left := 0    right := 0    for i := from; i <= to; i++ {        if i == iPivot {            continue        }        v := data[i]        if v <= vPivot {            self.mLeftStack.Push(v)            left++        } else {            self.mRightStack.Push(v)            right++        }    }    // pop right stack    p := to    for i := right; i > 0; i-- {        e,v := self.mRightStack.Pop()        if e != nil {            panic(e)        }        data[p] = v        p--    }    // pop pivot    data[p] = vPivot    p--    // pop left stack    for i := left; i > 0; i-- {        e,v := self.mLeftStack.Pop()        if e != nil {            panic(e)        }        data[p] = v        p--    }    // qsort left and right    self.qsort(data, from, from + left - 1)    self.qsort(data, to - right + 1, to)}

策略模式小结

策略模式的长处(1)策略模式合乎开闭准则。(2)防止应用多重条件转移语句,如if...else语句、switch...case语句(3)应用策略模式能够进步算法的保密性和安全性。策略模式的毛病(1)客户端必须晓得所有的策略,并且自行决定应用哪一个策略类。(2)代码中会产生十分多策略类,减少保护难度。(摘自 谭勇德 <<设计模式就该这样学>>)

(end)