1. چیست الگوی Iterator

الگوی Iterator یک الگوی طراحی رفتاری است که یک روش یکپارچه برای گذر از عناصر یک شیء تجمعی را بدون افشای نمایش داخلی شیء تجمعی فراهم می‌کند.

2. ویژگی‌ها و مزایای الگوی Iterator

ویژگی‌ها و مزایای الگوی Iterator به شرح زیر است:

  • می‌تواند ساختار داخلی شیء مجموعه را مخفی کند و الگوریتم گذر را از شیء مجموعه جدا کند.
  • روش استانداردی برای گذر از انواع مختلف اشیاء مجموعه فراهم می‌آورد.
  • کد مشتری را ساده‌تر و مفهومی‌تر می‌کند.
  • می‌تواند انواع مختلف Iteratorها را فراهم کند تا با نیازهای گذر مختلف سازگار شود.

3. نمونه‌های کاربردی عملی از الگوی Iterator

الگوی Iterator کاربردهای عملی بسیاری دارد، مانند:

  • گذر از مجموعه نتایج پرس و جوی پایگاه داده.
  • گذر از فایل‌ها و پوشه‌ها در سیستم فایل.
  • گذر از عناصر در یک مجموعه.

4. پیاده‌سازی الگوی Iterator در Golang

4.1 نمودار کلاس UML

الگوی Iterator در Golang

4.2 معرفی نمونه

در نمودار کلاس UML بالا، دو نقش اصلی داریم: Iterator و Collection.

  • Iterator رابط را برای گذر از یک شیء مجموعه تعریف می‌کند که شامل متد HasNext() برای تعیین وجود عنصر دیگر و متد Next() برای گرفتن عنصر بعدی است.
  • ConcreteIterator کلاس اجرایی خاص Iterator است که متد HasNext() و Next() را پیاده‌سازی می‌کند.
  • Collection رابط را برای ایجاد اشیاء Iterator، با متد CreateIterator()، تعریف می‌کند.
  • ConcreteCollection کلاس اجرایی خاص Collection است که متد CreateIterator() را پیاده‌سازی می‌کند.

4.3 مراحل پیاده‌سازی

بعداً، ما الگوی Iterator را به زبان Golang گام به گام پیاده‌سازی خواهیم کرد.

4.3.1 تعریف رابط Iterator و کلاس Concrete Iterator

type Iterator interface {
    HasNext() bool
    Next() interface{}
}

type ConcreteIterator struct {
    collection *ConcreteCollection
    index      int
}

func (it *ConcreteIterator) HasNext() bool {
    if it.index < len(it.collection.items) {
        return true
    }
    return false
}

func (it *ConcreteIterator) Next() interface{} {
    if it.HasNext() {
        item := it.collection.items[it.index]
        it.index++
        return item
    }
    return nil
}

4.3.2 تعریف رابط شیء Iterable و کلاس شیء Iterable Concrete

type Collection interface {
    CreateIterator() Iterator
}

type ConcreteCollection struct {
    items []interface{}
}

func (c *ConcreteCollection) CreateIterator() Iterator {
    return &ConcreteIterator{
        collection: c,
        index:      0,
    }
}

4.3.3 پیاده‌سازی منطق تولید Iterator در کلاس شیء Iterable

func main() {
    collection := &ConcreteCollection{
        items: []interface{}{"Golang", "Python", "Java"},
    }

    iterator := collection.CreateIterator()
    for iterator.HasNext() {
        item := iterator.Next()
        fmt.Println(item)
    }
}

اجرای کد بالا خروجی زیر را تولید خواهد کرد:

Golang
Python
Java

در کد بالا، ما یک کلاس ConcreteCollection را تعریف می‌کنیم که رابط Collection را پیاده‌سازی می‌کند، و با متد CreateIterator() اشیاء Iterator را برمی‌گرداند. ما از این اشیاء Iterator در تابع main() برای گذر استفاده می‌کنیم.

4.4 گام اجرایی گسترش: ساده‌سازی پیاده‌سازی ایتریتور با استفاده از تابع تولید کننده

در Golang، می‌توانیم با استفاده از تابع تولید کننده (yield)، پیاده‌سازی ایتریتورها را ساده‌تر کنیم. در ادامه، یک مثال از استفاده از تابع تولید کننده آمده است:

func GenerateItems() <-chan interface{} {
    items := []interface{}{"Golang", "Python", "Java"}

    out := make(chan interface{})
    go func() {
        defer close(out)
        for _, item := range items {
            out <- item
        }
    }()
    return out
}

func main() {
    for item := range GenerateItems() {
        fmt.Println(item)
    }
}

در کد فوق، یک تابع به نام GenerateItems() تعریف شده است که یک کانال فقط‐خواندنی (<-chan) را برمی‌گرداند و از yield برای به ترتیب ارسال عناصر به کانال درون این تابع استفاده می‌کند. در تابع main()، از range برای گذر از این کانال فقط‐خواندنی و خروجی دادن مقادیر عناصر استفاده می‌شود.

به این ترتیب، ما پیاده‌سازی ایتریتور را با استفاده از یک تابع تولید کننده ساده‌سازی کرده‌ایم.