【设计模式】17、iterator 迭代器模式

时间:2024-05-07 07:56:25

文章目录

  • 十七、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,
	}
}

相关文章