go委托模式
:
首先,我们先声明一个数据容器,其中有 Add()、 Delete() 和 Contains() 方法。还有一个转字符串的方法。
type IntSet struct {
data map[int]bool
}
func NewIntSet() IntSet {
return IntSet{make(map[int]bool)}
}
func (set *IntSet) Add(x int) {
set.data[x] = true
}
func (set *IntSet) Delete(x int) {
delete(set.data, x)
}
func (set *IntSet) Contains(x int) bool {
return set.data[x]
}
func (set *IntSet) String() string { // Satisfies fmt.Stringer interface
if len(set.data) == 0 {
return "{}"
}
ints := make([]int, 0, len(set.data))
for i := range set.data {
ints = append(ints, i)
}
sort.Ints(ints)
parts := make([]string, 0, len(ints))
for _, i := range ints {
parts = append(parts, fmt.Sprint(i))
}
return "{" + strings.Join(parts, ",") + "}"
}
我们如下使用这个数据容器:
ints := NewIntSet()
for _, i := range []int{1, 3, 5, 7} {
ints.Add(i)
fmt.Println(ints)
}
for _, i := range []int{1, 2, 3, 4, 5, 6, 7} {
fmt.Print(i, ints.Contains(i), " ")
ints.Delete(i)
fmt.Println(ints)
}
//
//type IntSet struct {
// data map[int]bool
//}
//
//func NewIntSet() IntSet {
// return IntSet{make(map[int]bool)}
//}
func (set *IntSet) Add(x int) {
set.data[x] = true
}
func (set *IntSet) Delete(x int) {
delete(set.data, x)
}
func (set *IntSet) Contains(x int) bool {
return set.data[x]
}
func (set *IntSet) String() string { // Satisfies fmt.Stringer interface
if len(set.data) == 0 {
return "{}"
}
ints := make([]int, 0, len(set.data))
for i := range set.data {
ints = append(ints, i)
}
sort.Ints(ints)
parts := make([]string, 0, len(ints))
for _, i := range ints {
parts = append(parts, fmt.Sprint(i))
}
return "{" + strings.Join(parts, ",") + "}"
}
// UndoableIntSet Poor style
type UndoableIntSet struct {
IntSet // Embedding (delegation)
functions []func()
}
func NewUndoableIntSet() UndoableIntSet {
return UndoableIntSet{NewIntSet(), nil}
}
func (set *UndoableIntSet) Add(x int) { // Override
if !set.Contains(x) {
set.data[x] = true
set.functions = append(set.functions, func() { set.Delete(x) })
} else {
set.functions = append(set.functions, nil)
}
}
func (set *UndoableIntSet) Delete(x int) { // Override
if set.Contains(x) {
delete(set.data, x)
set.functions = append(set.functions, func() { set.Add(x) })
} else {
set.functions = append(set.functions, nil)
}
}
func (set *UndoableIntSet) Undo() error {
if len(set.functions) == 0 {
return errors.New("No functions to undo")
}
index := len(set.functions) - 1
if function := set.functions[index]; function != nil {
function()
set.functions[index] = nil // Free closure for garbage collection
}
set.functions = set.functions[:index]
return nil
}
//但是,需要注意的是,我们用了一个新的 UndoableIntSet 几乎重写了所有的 IntSet 和 “写” 相关的方法,这样就可以把操作记录下来,然后 Undo 了。
//
//但是,可能别的类也需要 Undo 的功能,我是不是要重写所有的需要这个功能的类啊?这样的代码类似,就是因为数据容器不一样,我就要去重写它们,这太二了。
//
//我们能不能利用前面学到的泛型编程、函数式编程、IoC 等范式来把这个事干得好一些呢?当然是可以的。
//我们先声明一个 Undo[] 的函数数组(其实是一个栈)。
//
//并实现一个通用 Add()。其需要一个函数指针,并把这个函数指针存放到 Undo[] 函数数组中。
//
//在 Undo() 的函数中,我们会遍历Undo[]函数数组,并执行之,执行完后就弹栈。
type Undo []func()
func (undo *Undo) Add(function func()) {
*undo = append(*undo, function)
}
func (undo *Undo) Undo() error {
functions := *undo
if len(functions) == 0 {
return errors.New("No functions to undo")
}
index := len(functions) - 1
if function := functions[index]; function != nil {
function()
functions[index] = nil // Free closure for garbage collection
}
*undo = functions[:index]
return nil
}
type IntSet struct {
data map[int]bool
undo Undo
}
func NewIntSet() IntSet {
return IntSet{data: make(map[int]bool)}
}
//然后在其中的 Add 和 Delete中实现 Undo 操作。
//
//Add 操作时加入 Delete 操作的 Undo。
//Delete 操作时加入 Add 操作的 Undo。
func (set *IntSet) Add(x int) {
if !set.Contains(x) {
set.data[x] = true
set.undo.Add(func() { set.Delete(x) })
} else {
set.undo.Add(nil)
}
}
func (set *IntSet) Delete(x int) {
if set.Contains(x) {
delete(set.data, x)
set.undo.Add(func() { set.Add(x) })
} else {
set.undo.Add(nil)
}
}
func (set *IntSet) Undo() error {
return set.undo.Undo()
}
func (set *IntSet) Contains(x int) bool {
return set.data[x]
}