文章目录
- 十七、iterator 迭代器模式
- 17.1 user_slice
- 17.1.1 collection_test.go
- 17.1.2 collection.go
- 17.1.3 iterator.go
- 17.1.4 user.go
- 17.2 book_shelf
- 17.2.1 book_shelf_test.go
- 17.2.2 book_shelf.go
- 17.2.3 iterator.go
- 17.2.4 book.go
十七、iterator 迭代器模式
https://refactoringguru.cn/design-patterns/iterator
为了集合数据的安全性, 或方便迭代, 可以用迭代器接口. 屏蔽复杂的内部逻辑, 外部只能使用迭代器遍历
源码路径:godp/17iterator at master · datager/godp · GitHub
17.1 user_slice
├── collection.go
├── collection_test.go
├── iterator.go
├── readme.md
└── user.go
17.1.1 collection_test.go
package _71user_slice
import (
"fmt"
"testing"
)
/*
=== RUN TestCollection
1 Tom
2 Jack
--- PASS: TestCollection (0.00s)
PASS
*/
func TestCollection(t *testing.T) {
c := UserCollection{users: []*User{&User{"1", "Tom"}, {"2", "Jack"}}}
iter := c.createIterator()
for iter.hasNext() {
v := iter.getNext()
fmt.Println(v.ID, v.Name)
}
}
17.1.2 collection.go
package _71user_slice
type Collection interface {
createIterator() Iterator
}
type UserCollection struct {
users []*User
}
func (uc *UserCollection) createIterator() Iterator {
return &userIterator{
users: uc.users,
}
}
17.1.3 iterator.go
package _71user_slice
type Iterator interface {
hasNext() bool
getNext() *User
}
type userIterator struct {
index int
users []*User
}
func (ui *userIterator) hasNext() bool {
return ui.index < len(ui.users)
}
func (ui *userIterator) getNext() *User {
if ui.hasNext() {
v := ui.users[ui.index]
ui.index++
return v
}
return nil
}
17.1.4 user.go
package _71user_slice
type User struct {
ID string
Name string
}
17.2 book_shelf
图解设计模式 1.7 练习题
iterator 模式, 可以抽象出 迭代的操作, 无论内部数据结构是数组, 或链表, 或树, 都可以. 外部都可以用同样的接口访问.
本例, 分别用 数组, 和链表实现
├── book.go
├── book_shelf.go
├── book_shelf_test.go
├── iterator.go
└── readmd.md
17.2.1 book_shelf_test.go
package _72bookshelf
import (
"github.com/stretchr/testify/require"
"testing"
)
/*
=== RUN TestBookShelf
book_shelf_test.go:21: 算子开发
book_shelf_test.go:21: 编译器
book_shelf_test.go:21: 算子开发
book_shelf_test.go:21: 编译器
--- PASS: TestBookShelf (0.00s)
PASS
*/
func TestBookShelf(t *testing.T) {
bookShelves := []bookShelf{NewBookShelfBySlice(), NewBookShelfByList()}
for _, bs := range bookShelves {
bookNames := []string{"算子开发", "编译器"} // 测试数据
for _, name := range bookNames {
bs.addBook(NewBook(name))
}
it := bs.iterator()
idx := 0
for it.hasNext() {
b := it.next()
require.EqualValues(t, bookNames[idx], b.getName())
t.Log(b.getName())
idx++
}
}
}
17.2.2 book_shelf.go
package _72bookshelf
import "container/list"
// 书架接口
type bookShelf interface {
// 创建迭代器
iterator() iterator
// 辅助业务:
addBook(book)
}
// 书架: 数组实现
type bookShelfBySlice struct {
books []book
}
func NewBookShelfBySlice() bookShelf {
return &bookShelfBySlice{make([]book, 0)}
}
func (bs *bookShelfBySlice) iterator() iterator {
return NewBookShelfBySliceIterator(bs)
}
func (bs *bookShelfBySlice) addBook(b book) {
bs.books = append(bs.books, b)
}
// 书架: 链表实现
type bookShelfByList struct {
bookList *list.List
}
func NewBookShelfByList() bookShelf {
return &bookShelfByList{
bookList: list.New(),
}
}
func (bs *bookShelfByList) iterator() iterator {
return NewBookShelfByListIterator(bs)
}
func (bs *bookShelfByList) addBook(b book) {
bs.bookList.PushBack(b)
}
17.2.3 iterator.go
package _72bookshelf
import "container/list"
// 迭代器接口
type iterator interface {
hasNext() bool
next() book
}
// -------
// 书架迭代器: 基于数组的书架
type bookShelfBySliceIterator struct {
index int // 迭代器下标
bookShelf *bookShelfBySlice // 被迭代的对象
}
func (bsi *bookShelfBySliceIterator) hasNext() bool {
return bsi.index < len(bsi.bookShelf.books)
}
func (bsi *bookShelfBySliceIterator) next() book {
v := bsi.bookShelf.books[bsi.index]
bsi.index++
return v
}
func NewBookShelfBySliceIterator(bs *bookShelfBySlice) iterator {
return &bookShelfBySliceIterator{bookShelf: bs, index: 0}
}
// -------
// 书架迭代器: 基于链表的书架
type bookShelfByListIterator struct {
curBook *list.Element // 迭代器下标
bookShelf *bookShelfByList // 被迭代的对象
}
func (bsl *bookShelfByListIterator) hasNext() bool {
return bsl.curBook != nil
}
func (bsl *bookShelfByListIterator) next() book {
v := bsl.curBook
bsl.curBook = bsl.curBook.Next()
return v.Value.(book)
}
func NewBookShelfByListIterator(bs *bookShelfByList) iterator {
return &bookShelfByListIterator{bookShelf: bs, curBook: bs.bookList.Front()}
}
17.2.4 book.go
package _72bookshelf
import (
"math/rand"
"time"
)
type book interface {
getName() string
}
type bookImpl struct {
id int
name string
}
func (b *bookImpl) getName() string {
return b.name
}
func NewBook(name string) book {
rand.NewSource(time.Now().UnixMilli())
return &bookImpl{
id: rand.Int(),
name: name,
}
}