A realization undo

Delegation mechanism

package main

import (
    "errors"
    "fmt"
    "sort"
    "strings"
)

type InSet struct {
    data map[int]bool
    undo Undo
}

type UndoableInSet struct {
    InSet
    functions []func()
}

func NewUndoableInSet() UndoableInSet {
    return UndoableInSet{NewInSet(), nil}
}

func (set *UndoableInSet) Delete(x int) {
    if set.Contains(x) {
        delete(set.data, x)
        set.functions = append(set.functions, func() {
            set.Add(x)
        })
    }
}

func (set *UndoableInSet) Add(x int) {
    if !set.Contains(x) {
        set.data[x] = true
        set.functions = append(set.functions, func() {
            set.Delete(x)
        })
    }
}

func (set *UndoableInSet) 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
    }
    set.functions = set.functions[:index]
    return nil
}



func NewInSet() InSet {
    return InSet{data:make(map[int]bool)}
}

func (set *InSet) 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 *InSet) 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 *InSet) Contains(x int) bool {
    return set.data[x]
}

func (set *InSet) Undo() error {
    return set.undo.Undo()
}

func (set *InSet) String() string {
    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, ",") + "}"
}

func main() {
    ints := NewUndoableInSet()
    for _, i := range []int{1, 2, 3, 4} {
        ints.Add(i)
        fmt.Println(ints)
    }
    fmt.Println()
    for {
        if err := ints.Undo(); err != nil {
            break
        }
        fmt.Println(ints)
    }
}

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
    }
    *undo = functions[:index]
    return nil
}

 

Reference from Chen Hao geeks time  https://time.geekbang.org/column/article/2748

end

Guess you like

Origin www.cnblogs.com/CherryTab/p/12404819.html