diff --git a/behavior/04_iterator/README.md b/behavior/04_iterator/README.md index 788872b..43a4b0d 100644 --- a/behavior/04_iterator/README.md +++ b/behavior/04_iterator/README.md @@ -4,8 +4,21 @@ 迭代器模式在各种语言中都有很深入,很广泛的应用,迭代器模式就是,对这种存在于语言中的基本模式的进一步应用。 +迭代器模式中的两个重要的接口: -迭代器是一种管理数据的方式。 +```go +type Iterator interface { +//定义迭代器可以进行的动作 + Next() +//... +} +type IEnumerator interface { + //返回一个迭代器接口 + Iterator() Iterator +} +``` + +迭代器是一种管理数据的方式,往往需要一个管理数据的内在容器/集合/链表/栈等结构,需要注意的是,一般在访问上不实现为链表的访问方式,而使用滑动游标的方式。 现实生活中的景区的地图指南就是一个很好的迭代器的例子,地图就是一个迭代器,不论是哪个景区,都能通过一张地图(或者说这个迭代器),让你明白当前景区的景点数,最佳参观顺序等,游客只需要按照迭代器的方式去访问景点即可。 diff --git a/behavior/04_iterator/iterator.go b/behavior/04_iterator/iterator.go index 8c83493..7552e2e 100644 --- a/behavior/04_iterator/iterator.go +++ b/behavior/04_iterator/iterator.go @@ -3,55 +3,76 @@ package iterator //////////////////////////////// //使用景点例子 -//ITouristMap 游客地图是一个迭代器Iterator,为用户提供当前景区中不同景点的统一访问能力 -type ITouristMap interface { - FirstPot() //首个景点 - IsLastPot() bool //当前景点是否是最后一个 - Next() interface{} //下一个景点 +//Iterator 游客地图是一个迭代器Iterator,为用户提供当前景区中不同景点的统一访问能力 +type Iterator interface { + Reset() //重置 + FirstPot() IPot //首个景点 + IsLastPot() bool //当前景点是否是最后一个 + Next() IPot //下一个景点 } -//IScenicArea 是一个针对景区的Aggregate聚合类型接口,返回一个迭代器接口 -//IScenicArea 返回一个游客访问接口 -type IScenicArea interface { - Iterator() ITouristMap +//IPot 景点对象的接口 +type IPot interface { + Visit() //景点可以参观 } //ScenicArea 景区包含所有的景点 type ScenicArea struct { - count int //景点的数量 - pots []interface{} //景点列表,景区可能一直在开发新的景点,所以景区的数量可能一直在增长 + count int //景点的数量 + pots []IPot //景点列表,景区可能一直在开发新的景点,所以景区的数量可能一直在增长 } -//Iterator 通过 -func (s *ScenicArea) Iterator() ITouristMap { - return &ScenicAreaPotsMap{ - numbers: n, - next: n.start, +//PotsIterator 实现景区景点迭代器的对象 +//PotsIterator 该对象的目的就是为了隐藏景区本身 +//PotsIterator 实现为一个游标迭代器 +type PotsIterator struct { + cursor int + potsSlice []IPot +} + +//Iterator 返回一个接待 +func (s *ScenicArea) Iterator() Iterator { + return &PotsIterator{ + cursor: 0, + potsSlice: s.pots, } } -//ScenicAreaPotsMap 就是景区提供的迭代器类型,要实现具体的景区景点的迭代访问能力 -type ScenicAreaPotsMap struct { - numbers *Numbers - next int +//AddPot 添加景点 +func (s *ScenicArea) AddPot(pots ...IPot) { + for i := range pots { + s.count++ + s.pots = append(s.pots, pots[i]) + } +} + +//PotsCount 添加景点 +func (s *ScenicArea) PotsCount() int { + return s.count +} + +//Reset 重置 +func (s *PotsIterator) Reset() { + s.cursor = 0 } //FirstPot 第一个景点 -func (i *ScenicAreaPotsMap) FirstPot() { - i.next = i.numbers.start +func (s *PotsIterator) FirstPot() IPot { + return s.potsSlice[0] } -//IsLastPot 是否是最后一个 -func (i *ScenicAreaPotsMap) IsLastPot() bool { - return i.next > i.numbers.end +//IsLastPot 判断游标的位置 +func (s *PotsIterator) IsLastPot() bool { + return s.cursor == -1 } //Next 去路线上的下一个景点 -func (i *ScenicAreaPotsMap) Next() interface{} { - if !i.IsDone() { - next := i.next - i.next++ - return next +func (s *PotsIterator) Next() IPot { + if s.cursor+1 == len(s.potsSlice) { + s.cursor = -1 //设置到最后 + return nil } - return nil + s.cursor++ + return s.potsSlice[s.cursor] + } diff --git a/behavior/04_iterator/iterator_test.go b/behavior/04_iterator/iterator_test.go index a508289..ac2f580 100644 --- a/behavior/04_iterator/iterator_test.go +++ b/behavior/04_iterator/iterator_test.go @@ -1,19 +1,52 @@ package iterator -func ExampleIterator() { - var aggregate Aggregate - aggregate = NewNumbers(1, 10) +import ( + "fmt" + "testing" +) - IteratorPrint(aggregate.Iterator()) - // Output: - // 1 - // 2 - // 3 - // 4 - // 5 - // 6 - // 7 - // 8 - // 9 - // 10 +//ChildPot 儿童景点 +type ChildPot struct { + Name string +} + +func (c *ChildPot) Visit() { + fmt.Println("i am: ", c.Name) +} +func TestIterator(t *testing.T) { + + scenicArea := ScenicArea{} + + scenicArea.AddPot(&ChildPot{Name: "monkey garden"}, &ChildPot{Name: "fairy country"}, &ChildPot{Name: "future space"}) + + t.Log("pots count:", scenicArea.PotsCount()) + + potInterator := scenicArea.Iterator() + + pot := potInterator.FirstPot() + + t.Logf("first pot: %#v\n", pot) + + VisitAllPots(potInterator) + + t.Log("add a pot", "pot: count", scenicArea.PotsCount()) + + scenicArea.AddPot(&ChildPot{Name: "virtual world"}) + + t.Log("pots count:", scenicArea.PotsCount()) + + //切片变了,要重新获取 + potInterator = scenicArea.Iterator() + + potInterator.Reset() + + VisitAllPots(potInterator) + +} + +func VisitAllPots(i Iterator) { + for c := i.FirstPot(); !i.IsLastPot(); c = i.Next() { + c.Visit() + fmt.Printf("finish visit pot : %#v\n", c) + } } diff --git a/go.mod b/go.mod index 6fbc91b..ac9fa4e 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,7 @@ module github.com/crazybber/go-fucking-algorithm go 1.14 -require github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381 +require ( + github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381 + go.uber.org/zap v1.15.0 +) diff --git a/go.sum b/go.sum index 6823f4b..4f49e76 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,44 @@ +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381 h1:bqDmpDG49ZRnB5PcgP0RXtQvnMSgIF14M7CBd2shtXs= github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM= +go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=