---
title: "المُكرِّر"
type: "design-pattern"
slug: "iterator"
url: "http://localhost:3000/ar/design-patterns/iterator.md"
category: "الأنماط السلوكية"
description: "المُكرِّر هو نمط تصميم سلوكي يتيح لك التنقل عبر عناصر المجموعة دون الكشف عن تمثيلها الداخلي (قائمة، مكدس، شجرة، إلخ)."
languages: ["java", "csharp", "cpp", "go", "php", "python", "ruby", "rust", "swift", "typescript"]
---
# المُكرِّر

> المُكرِّر هو نمط تصميم سلوكي يتيح لك التنقل عبر عناصر المجموعة دون الكشف عن تمثيلها الداخلي (قائمة، مكدس، شجرة، إلخ).

## Intent

**المُكرِّر** هو نمط تصميم سلوكي يتيح لك التنقل عبر عناصر المجموعة دون الكشف عن تمثيلها الداخلي (قائمة، مكدس، شجرة، إلخ).

## Problem

تُعدّ المجموعات من أكثر أنواع البيانات استخداماً في البرمجة. ومع ذلك، فالمجموعة ليست سوى حاوية لمجموعة من الكائنات.

أنواع مختلفة من المجموعات.

تخزن معظم المجموعات عناصرها في قوائم بسيطة. غير أن بعضها يعتمد على مكدسات أو أشجار أو رسوم بيانية أو هياكل بيانات معقدة أخرى.

ولكن بغض النظر عن كيفية تنظيم المجموعة، يجب أن توفر وسيلة للوصول إلى عناصرها حتى يتمكن الكود الآخر من استخدامها. يجب أن تكون هناك طريقة للمرور على كل عنصر في المجموعة دون الوصول إلى نفس العناصر مراراً وتكراراً.

قد يبدو هذا مهمة سهلة إذا كانت لديك مجموعة مبنية على قائمة؛ فأنت فقط تتكرر على جميع العناصر. لكن كيف تجتاز عناصر بنية بيانات معقدة، مثل الشجرة، بشكل تسلسلي؟ على سبيل المثال، قد يكفيك في يوم ما الاجتياز بالعمق أولاً (depth-first) لشجرة ما. وفي اليوم التالي قد تحتاج إلى الاجتياز بالاتساع (breadth-first). وفي الأسبوع التالي قد تحتاج إلى شيء آخر، مثل الوصول العشوائي إلى عناصر الشجرة.

يمكن اجتياز نفس المجموعة بعدة طرق مختلفة.

إن إضافة المزيد والمزيد من خوارزميات الاجتياز إلى المجموعة يُضعف تدريجياً مسؤوليتها الأساسية، وهي تخزين البيانات بكفاءة. علاوة على ذلك، قد تكون بعض الخوارزميات مُصمَّمة لتطبيق معين، مما يجعل تضمينها في فئة مجموعة عامة أمراً غريباً.

من ناحية أخرى، قد لا يهتم كود العميل المفترض للعمل مع مجموعات مختلفة بكيفية تخزينها لعناصرها. غير أن المجموعات جميعها توفر طرقاً مختلفة للوصول إلى عناصرها، لذا لا يكون أمامك خيار سوى ربط كودك بفئات المجموعة المحددة.

## Solution

الفكرة الأساسية لنمط المُكرِّر هي استخراج سلوك اجتياز المجموعة إلى كائن منفصل يُسمى _المُكرِّر_.

تُنفِّذ المُكرِّرات خوارزميات اجتياز متنوعة. يمكن لعدة كائنات مُكرِّر اجتياز نفس المجموعة في الوقت ذاته.

إضافةً إلى تنفيذ الخوارزمية نفسها، يُغلِّف كائن المُكرِّر جميع تفاصيل الاجتياز، مثل الموضع الحالي وعدد العناصر المتبقية حتى النهاية. بفضل ذلك، يمكن لعدة مُكرِّرات اجتياز نفس المجموعة في وقت واحد باستقلالية تامة عن بعضها البعض.

عادةً، توفر المُكرِّرات طريقة رئيسية واحدة لجلب عناصر المجموعة. يمكن للعميل الاستمرار في تشغيل هذه الطريقة حتى لا تُعيد شيئاً، مما يعني أن المُكرِّر قد اجتاز جميع العناصر.

يجب على جميع المُكرِّرات تنفيذ الواجهة ذاتها. يجعل ذلك كود العميل متوافقاً مع أي نوع مجموعة أو أي خوارزمية اجتياز طالما يوجد مُكرِّر مناسب. وإذا احتجت إلى طريقة خاصة لاجتياز مجموعة، فأنت تنشئ فئة مُكرِّر جديدة فقط دون الحاجة إلى تغيير المجموعة أو العميل.

## Structure

1. تُعلِن واجهة **المُكرِّر** عن العمليات المطلوبة لاجتياز المجموعة: جلب العنصر التالي، واسترجاع الموضع الحالي، وإعادة تشغيل التكرار، إلخ.
2. تُنفِّذ **المُكرِّرات المُحدَّدة** خوارزميات محددة لاجتياز المجموعة. يجب على كائن المُكرِّر تتبع تقدم الاجتياز من تلقاء نفسه. يسمح ذلك لعدة مُكرِّرات باجتياز نفس المجموعة باستقلالية عن بعضها البعض.
3. تُعلِن واجهة **المجموعة** عن طريقة أو أكثر للحصول على مُكرِّرات متوافقة مع المجموعة. لاحظ أنه يجب إعلان نوع القيمة المُعادة من الطرق كواجهة المُكرِّر حتى تتمكن المجموعات المُحدَّدة من إرجاع أنواع متنوعة من المُكرِّرات.
4. تُعيد **المجموعات المُحدَّدة** نسخاً جديدة من فئة مُكرِّر مُحدَّد معينة في كل مرة يطلبها العميل. قد تتساءل أين بقية كود المجموعة؟ لا تقلق، يجب أن يكون في نفس الفئة. الأمر فقط أن هذه التفاصيل ليست ضرورية للنمط الفعلي، لذا نحذفها.
5. يعمل **العميل** مع المجموعات والمُكرِّرات عبر واجهاتها. بهذه الطريقة لا يرتبط العميل بالفئات المُحدَّدة، مما يتيح لك استخدام مجموعات ومُكرِّرات متنوعة مع نفس كود العميل.
عادةً، لا ينشئ العملاء المُكرِّرات بأنفسهم، بل يحصلون عليها من المجموعات. ولكن في حالات معينة، يمكن للعميل إنشاء مُكرِّر مباشرةً؛ على سبيل المثال، عندما يعرِّف العميل مُكرِّره الخاص المميز.

## Pseudocode

في هذا المثال، يُستخدَم نمط **المُكرِّر** للتنقل عبر نوع خاص من المجموعات التي تُغلِّف الوصول إلى الرسم البياني الاجتماعي لـ Facebook. توفر المجموعة عدة مُكرِّرات يمكنها اجتياز الملفات الشخصية بطرق متنوعة.

مثال على التكرار عبر ملفات اجتماعية شخصية.

يمكن استخدام مُكرِّر ‘friends’ للتنقل عبر أصدقاء ملف شخصي معين. أما مُكرِّر ‘colleagues’ فيفعل الشيء نفسه، باستثناء أنه يتجاوز الأصدقاء الذين لا يعملون في نفس الشركة مثل الشخص المستهدف. كلا المُكرِّرَين يُنفِّذان واجهة مشتركة تتيح للعملاء جلب الملفات الشخصية دون الخوض في تفاصيل التنفيذ مثل المصادقة وإرسال طلبات REST.

لا يرتبط كود العميل بالفئات المُحدَّدة لأنه يعمل مع المجموعات والمُكرِّرات فقط من خلال الواجهات. إذا قررت ربط تطبيقك بشبكة اجتماعية جديدة، فأنت تحتاج فقط إلى توفير فئات مجموعة ومُكرِّر جديدة دون تغيير الكود الموجود.

// يجب أن تُعلِن واجهة المجموعة عن أسلوب مصنع
// لإنتاج المُكرِّرات. يمكنك إعلان عدة طرق إذا كانت
// هناك أنواع مختلفة من التكرار متاحة في برنامجك.
interface SocialNetwork is
    method createFriendsIterator(profileId):ProfileIterator
    method createCoworkersIterator(profileId):ProfileIterator

// كل مجموعة مُحدَّدة مرتبطة بمجموعة من فئات المُكرِّرات
// المُحدَّدة التي تُعيدها. لكن العميل ليس كذلك، إذ
// توقيع هذه الطرق يُعيد واجهات المُكرِّر.
class Facebook implements SocialNetwork is
    // ... يجب وضع معظم كود المجموعة هنا ...

    // كود إنشاء المُكرِّر.
    method createFriendsIterator(profileId) is
        return new FacebookIterator(this, profileId, "friends")
    method createCoworkersIterator(profileId) is
        return new FacebookIterator(this, profileId, "coworkers")

// الواجهة المشتركة لجميع المُكرِّرات.
interface ProfileIterator is
    method getNext():Profile
    method hasMore():bool

// فئة المُكرِّر المُحدَّد.
class FacebookIterator implements ProfileIterator is
    // يحتاج المُكرِّر إلى مرجع للمجموعة التي
    // يجتازها.
    private field facebook: Facebook
    private field profileId, type: string

    // يجتاز كائن المُكرِّر المجموعة باستقلالية
    // عن المُكرِّرات الأخرى. لذلك يجب أن يخزن
    // حالة التكرار.
    private field currentPosition
    private field cache: array of Profile

    constructor FacebookIterator(facebook, profileId, type) is
        this.facebook = facebook
        this.profileId = profileId
        this.type = type

    private method lazyInit() is
        if (cache == null)
            cache = facebook.socialGraphRequest(profileId, type)

    // كل فئة مُكرِّر مُحدَّدة لها تنفيذها الخاص
    // لواجهة المُكرِّر المشتركة.
    method getNext() is
        if (hasMore())
            result = cache[currentPosition]
            currentPosition++
            return result

    method hasMore() is
        lazyInit()
        return currentPosition < cache.length

// إليك حيلة أخرى مفيدة: يمكنك تمرير مُكرِّر إلى
// فئة عميل بدلاً من منحه وصولاً إلى مجموعة
// كاملة. بهذه الطريقة، لا تكشف المجموعة للعميل.
//
// وهناك فائدة أخرى: يمكنك تغيير طريقة عمل
// العميل مع المجموعة أثناء التشغيل عن طريق تمريره
// مُكرِّراً مختلفاً. وهذا ممكن لأن كود العميل
// ليس مرتبطاً بفئات المُكرِّر المُحدَّدة.
class SocialSpammer is
    method send(iterator: ProfileIterator, message: string) is
        while (iterator.hasMore())
            profile = iterator.getNext()
            System.sendEmail(profile.getEmail(), message)

// تُهيِّئ فئة التطبيق المجموعات والمُكرِّرات
// ثم تمررها إلى كود العميل.
class Application is
    field network: SocialNetwork
    field spammer: SocialSpammer

    method config() is
        if working with Facebook
            this.network = new Facebook()
        if working with LinkedIn
            this.network = new LinkedIn()
        this.spammer = new SocialSpammer()

    method sendSpamToFriends(profile) is
        iterator = network.createFriendsIterator(profile.getId())
        spammer.send(iterator, "Very important message")

    method sendSpamToCoworkers(profile) is
        iterator = network.createCoworkersIterator(profile.getId())
        spammer.send(iterator, "Very important message")

## Applicability

استخدم نمط المُكرِّر عندما تحتوي مجموعتك على بنية بيانات معقدة في الخلفية، لكنك تريد إخفاء هذا التعقيد عن العملاء (سواءً لأسباب تتعلق بالراحة أو الأمان).

 يُغلِّف المُكرِّر تفاصيل العمل مع بنية البيانات المعقدة، مما يوفر للعميل عدة طرق بسيطة للوصول إلى عناصر المجموعة. وفي حين أن هذا النهج مريح جداً للعميل، فإنه يحمي أيضاً المجموعة من الإجراءات المتهورة أو الخبيثة التي قد يقوم بها العميل لو عمل مع المجموعة مباشرةً.

 استخدم النمط للحد من تكرار كود الاجتياز في تطبيقك.

 يميل كود خوارزميات التكرار غير البديهية إلى أن يكون ضخماً جداً. وعند وضعه داخل منطق الأعمال في التطبيق، قد يُعتِّم على مسؤولية الكود الأصلي ويجعله أصعب في الصيانة. ونقل كود الاجتياز إلى مُكرِّرات مخصصة يساعدك على جعل كود التطبيق أكثر إيجازاً ونظافة.

 استخدم نمط المُكرِّر عندما تريد لكودك القدرة على اجتياز هياكل بيانات مختلفة أو عندما تكون أنواع هذه الهياكل غير معروفة مسبقاً.

 يوفر النمط واجهتين عامتين للمجموعات والمُكرِّرات على حد سواء. وبما أن كودك يستخدم هذه الواجهات الآن، فسيستمر في العمل إذا مررت له أنواعاً مختلفة من المجموعات والمُكرِّرات التي تُنفِّذ هذه الواجهات.

## How to Implement

1. أعلِن عن واجهة المُكرِّر. على أقل تقدير، يجب أن تحتوي على طريقة لجلب العنصر التالي من المجموعة. لكن من أجل الراحة يمكنك إضافة بعض الطرق الأخرى، مثل جلب العنصر السابق وتتبع الموضع الحالي والتحقق من نهاية التكرار.
2. أعلِن عن واجهة المجموعة وصِف فيها طريقة لجلب المُكرِّرات. يجب أن يكون نوع القيمة المُعادة مماثلاً لنوع واجهة المُكرِّر. يمكنك إعلان طرق مماثلة إذا كنت تخطط لامتلاك عدة مجموعات متميزة من المُكرِّرات.
3. نفِّذ فئات مُكرِّر مُحدَّدة للمجموعات التي تريد اجتيازها بالمُكرِّرات. يجب أن يكون كائن المُكرِّر مرتبطاً بنسخة واحدة من المجموعة. عادةً، يتم إنشاء هذا الارتباط عبر مُنشئ المُكرِّر.
4. نفِّذ واجهة المجموعة في فئات المجموعة الخاصة بك. الفكرة الأساسية هي توفير اختصار للعميل لإنشاء المُكرِّرات المُصمَّمة لفئة مجموعة معينة. يجب أن يمرر كائن المجموعة نفسه إلى مُنشئ المُكرِّر لإنشاء رابط بينهما.
5. راجع كود العميل واستبدل كل كود اجتياز المجموعة باستخدام المُكرِّرات. يجلب العميل كائن مُكرِّر جديداً في كل مرة يحتاج فيها إلى التكرار على عناصر المجموعة.

## Pros

* _مبدأ المسؤولية الفردية_. يمكنك تنظيف كود العميل والمجموعات عن طريق استخراج خوارزميات الاجتياز الضخمة في فئات منفصلة.
* _مبدأ الفتح/الإغلاق_. يمكنك تنفيذ أنواع جديدة من المجموعات والمُكرِّرات وتمريرها إلى الكود الموجود دون كسر أي شيء.
* يمكنك التكرار على نفس المجموعة بالتوازي لأن كل كائن مُكرِّر يحتوي على حالة التكرار الخاصة به.
* لنفس السبب، يمكنك تأجيل عملية التكرار والاستمرار فيها عند الحاجة.

## Cons

* قد يكون تطبيق النمط مبالغاً فيه إذا كان تطبيقك يعمل فقط مع مجموعات بسيطة.
* قد يكون استخدام مُكرِّر أقل كفاءة من الوصول المباشر إلى عناصر بعض المجموعات المتخصصة.

## Relations with Other Patterns

* يمكنك استخدام [المُكرِّرات](/ar/design-patterns/iterator) لاجتياز أشجار [المُرَكَّب](/ar/design-patterns/composite).
* يمكنك استخدام [أسلوب المصنع](/ar/design-patterns/factory-method) مع [المُكرِّر](/ar/design-patterns/iterator) للسماح للفئات الفرعية للمجموعات بإرجاع أنواع مختلفة من المُكرِّرات المتوافقة مع المجموعات.
* يمكنك استخدام [الميمنتو](/ar/design-patterns/memento) مع [المُكرِّر](/ar/design-patterns/iterator) لالتقاط حالة التكرار الحالية والتراجع عنها عند الضرورة.
* يمكنك استخدام [الزائر](/ar/design-patterns/visitor) مع [المُكرِّر](/ar/design-patterns/iterator) لاجتياز بنية بيانات معقدة وتنفيذ عملية على عناصرها، حتى لو كانت جميعها تنتمي إلى فئات مختلفة.
## Relations

**Related patterns**

- [المركَّب](/ar/design-patterns/composite.md)
- [طريقة المصنع](/ar/design-patterns/factory-method.md)
- [التذكار](/ar/design-patterns/memento.md)
- [الزائر](/ar/design-patterns/visitor.md)

## Code Examples

### java

```java
package refactoring_guru.iterator.example.iterators;

import refactoring_guru.iterator.example.profile.Profile;

public interface ProfileIterator {
    boolean hasNext();

    Profile getNext();

    void reset();
}

package refactoring_guru.iterator.example.iterators;

import refactoring_guru.iterator.example.profile.Profile;
import refactoring_guru.iterator.example.social_networks.Facebook;

import java.util.ArrayList;
import java.util.List;

public class FacebookIterator implements ProfileIterator {
    private Facebook facebook;
    private String type;
    private String email;
    private int currentPosition = 0;
    private List<String> emails = new ArrayList<>();
    private List<Profile> profiles = new ArrayList<>();

    public FacebookIterator(Facebook facebook, String type, String email) {
        this.facebook = facebook;
        this.type = type;
        this.email = email;
    }

    private void lazyLoad() {
        if (emails.size() == 0) {
            List<String> profiles = facebook.requestProfileFriendsFromFacebook(this.email, this.type);
            for (String profile : profiles) {
                this.emails.add(profile);
                this.profiles.add(null);
            }
        }
    }

    @Override
    public boolean hasNext() {
        lazyLoad();
        return currentPosition < emails.size();
    }

    @Override
    public Profile getNext() {
        if (!hasNext()) {
            return null;
        }

        String friendEmail = emails.get(currentPosition);
        Profile friendProfile = profiles.get(currentPosition);
        if (friendProfile == null) {
            friendProfile = facebook.requestProfileFromFacebook(friendEmail);
            profiles.set(currentPosition, friendProfile);
        }
        currentPosition++;
        return friendProfile;
    }

    @Override
    public void reset() {
        currentPosition = 0;
    }
}

package refactoring_guru.iterator.example.iterators;

import refactoring_guru.iterator.example.profile.Profile;
import refactoring_guru.iterator.example.social_networks.LinkedIn;

import java.util.ArrayList;
import java.util.List;

public class LinkedInIterator implements ProfileIterator {
    private LinkedIn linkedIn;
    private String type;
    private String email;
    private int currentPosition = 0;
    private List<String> emails = new ArrayList<>();
    private List<Profile> contacts = new ArrayList<>();

    public LinkedInIterator(LinkedIn linkedIn, String type, String email) {
        this.linkedIn = linkedIn;
        this.type = type;
        this.email = email;
    }

    private void lazyLoad() {
        if (emails.size() == 0) {
            List<String> profiles = linkedIn.requestRelatedContactsFromLinkedInAPI(this.email, this.type);
            for (String profile : profiles) {
                this.emails.add(profile);
                this.contacts.add(null);
            }
        }
    }

    @Override
    public boolean hasNext() {
        lazyLoad();
        return currentPosition < emails.size();
    }

    @Override
    public Profile getNext() {
        if (!hasNext()) {
            return null;
        }

        String friendEmail = emails.get(currentPosition);
        Profile friendContact = contacts.get(currentPosition);
        if (friendContact == null) {
            friendContact = linkedIn.requestContactInfoFromLinkedInAPI(friendEmail);
            contacts.set(currentPosition, friendContact);
        }
        currentPosition++;
        return friendContact;
    }

    @Override
    public void reset() {
        currentPosition = 0;
    }
}

package refactoring_guru.iterator.example.social_networks;

import refactoring_guru.iterator.example.iterators.ProfileIterator;

public interface SocialNetwork {
    ProfileIterator createFriendsIterator(String profileEmail);

    ProfileIterator createCoworkersIterator(String profileEmail);
}

package refactoring_guru.iterator.example.social_networks;

import refactoring_guru.iterator.example.iterators.FacebookIterator;
import refactoring_guru.iterator.example.iterators.ProfileIterator;
import refactoring_guru.iterator.example.profile.Profile;

import java.util.ArrayList;
import java.util.List;

public class Facebook implements SocialNetwork {
    private List<Profile> profiles;

    public Facebook(List<Profile> cache) {
        if (cache != null) {
            this.profiles = cache;
        } else {
            this.profiles = new ArrayList<>();
        }
    }

    public Profile requestProfileFromFacebook(String profileEmail) {
        // هنا سيكون طلب POST إلى إحدى نقاط نهاية Facebook API.
        // بدلاً من ذلك، نحاكي اتصالاً شبكياً طويلاً، كما تتوقعه
        // في الحياة الواقعية...
        simulateNetworkLatency();
        System.out.println("Facebook: Loading profile '" + profileEmail + "' over the network...");

        // ...وإرجاع بيانات الاختبار.
        return findProfile(profileEmail);
    }

    public List<String> requestProfileFriendsFromFacebook(String profileEmail, String contactType) {
        // هنا سيكون طلب POST إلى إحدى نقاط نهاية Facebook API.
        // بدلاً من ذلك، نحاكي اتصالاً شبكياً طويلاً، كما تتوقعه
        // في الحياة الواقعية...
        simulateNetworkLatency();
        System.out.println("Facebook: Loading '" + contactType + "' list of '" + profileEmail + "' over the network...");

        // ...وإرجاع بيانات الاختبار.
        Profile profile = findProfile(profileEmail);
        if (profile != null) {
            return profile.getContacts(contactType);
        }
        return null;
    }

    private Profile findProfile(String profileEmail) {
        for (Profile profile : profiles) {
            if (profile.getEmail().equals(profileEmail)) {
                return profile;
            }
        }
        return null;
    }

    private void simulateNetworkLatency() {
        try {
            Thread.sleep(2500);
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
    }

    @Override
    public ProfileIterator createFriendsIterator(String profileEmail) {
        return new FacebookIterator(this, "friends", profileEmail);
    }

    @Override
    public ProfileIterator createCoworkersIterator(String profileEmail) {
        return new FacebookIterator(this, "coworkers", profileEmail);
    }

}

package refactoring_guru.iterator.example.social_networks;

import refactoring_guru.iterator.example.iterators.LinkedInIterator;
import refactoring_guru.iterator.example.iterators.ProfileIterator;
import refactoring_guru.iterator.example.profile.Profile;

import java.util.ArrayList;
import java.util.List;

public class LinkedIn implements SocialNetwork {
    private List<Profile> contacts;

    public LinkedIn(List<Profile> cache) {
        if (cache != null) {
            this.contacts = cache;
        } else {
            this.contacts = new ArrayList<>();
        }
    }

    public Profile requestContactInfoFromLinkedInAPI(String profileEmail) {
        // هنا سيكون طلب POST إلى إحدى نقاط نهاية LinkedIn API.
        // بدلاً من ذلك، نحاكي اتصالاً شبكياً طويلاً، كما تتوقعه
        // في الحياة الواقعية...
        simulateNetworkLatency();
        System.out.println("LinkedIn: Loading profile '" + profileEmail + "' over the network...");

        // ...وإرجاع بيانات الاختبار.
        return findContact(profileEmail);
    }

    public List<String> requestRelatedContactsFromLinkedInAPI(String profileEmail, String contactType) {
        // هنا سيكون طلب POST إلى إحدى نقاط نهاية LinkedIn API.
        // بدلاً من ذلك، نحاكي اتصالاً شبكياً طويلاً، كما تتوقعه
        // في الحياة الواقعية.
        simulateNetworkLatency();
        System.out.println("LinkedIn: Loading '" + contactType + "' list of '" + profileEmail + "' over the network...");

        // ...وإرجاع بيانات الاختبار.
        Profile profile = findContact(profileEmail);
        if (profile != null) {
            return profile.getContacts(contactType);
        }
        return null;
    }

    private Profile findContact(String profileEmail) {
        for (Profile profile : contacts) {
            if (profile.getEmail().equals(profileEmail)) {
                return profile;
            }
        }
        return null;
    }

    private void simulateNetworkLatency() {
        try {
            Thread.sleep(2500);
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
    }

    @Override
    public ProfileIterator createFriendsIterator(String profileEmail) {
        return new LinkedInIterator(this, "friends", profileEmail);
    }

    @Override
    public ProfileIterator createCoworkersIterator(String profileEmail) {
        return new LinkedInIterator(this, "coworkers", profileEmail);
    }
}

package refactoring_guru.iterator.example.profile;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Profile {
    private String name;
    private String email;
    private Map<String, List<String>> contacts = new HashMap<>();

    public Profile(String email, String name, String... contacts) {
        this.email = email;
        this.name = name;

        // تحليل قائمة جهات الاتصال من مجموعة أزواج "friend:email@gmail.com".
        for (String contact : contacts) {
            String[] parts = contact.split(":");
            String contactType = "friend", contactEmail;
            if (parts.length == 1) {
                contactEmail = parts[0];
            }
            else {
                contactType = parts[0];
                contactEmail = parts[1];
            }
            if (!this.contacts.containsKey(contactType)) {
                this.contacts.put(contactType, new ArrayList<>());
            }
            this.contacts.get(contactType).add(contactEmail);
        }
    }

    public String getEmail() {
        return email;
    }

    public String getName() {
        return name;
    }

    public List<String> getContacts(String contactType) {
        if (!this.contacts.containsKey(contactType)) {
            this.contacts.put(contactType, new ArrayList<>());
        }
        return contacts.get(contactType);
    }
}

package refactoring_guru.iterator.example.spammer;

import refactoring_guru.iterator.example.iterators.ProfileIterator;
import refactoring_guru.iterator.example.profile.Profile;
import refactoring_guru.iterator.example.social_networks.SocialNetwork;

public class SocialSpammer {
    public SocialNetwork network;
    public ProfileIterator iterator;

    public SocialSpammer(SocialNetwork network) {
        this.network = network;
    }

    public void sendSpamToFriends(String profileEmail, String message) {
        System.out.println("\nIterating over friends...\n");
        iterator = network.createFriendsIterator(profileEmail);
        while (iterator.hasNext()) {
            Profile profile = iterator.getNext();
            sendMessage(profile.getEmail(), message);
        }
    }

    public void sendSpamToCoworkers(String profileEmail, String message) {
        System.out.println("\nIterating over coworkers...\n");
        iterator = network.createCoworkersIterator(profileEmail);
        while (iterator.hasNext()) {
            Profile profile = iterator.getNext();
            sendMessage(profile.getEmail(), message);
        }
    }

    public void sendMessage(String email, String message) {
        System.out.println("Sent message to: '" + email + "'. Message body: '" + message + "'");
    }
}

package refactoring_guru.iterator.example;

import refactoring_guru.iterator.example.profile.Profile;
import refactoring_guru.iterator.example.social_networks.Facebook;
import refactoring_guru.iterator.example.social_networks.LinkedIn;
import refactoring_guru.iterator.example.social_networks.SocialNetwork;
import refactoring_guru.iterator.example.spammer.SocialSpammer;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/**
 * فئة العرض التجريبي. كل شيء يتجمع هنا.
 */
public class Demo {
    public static Scanner scanner = new Scanner(System.in);

    public static void main(String[] args) {
        System.out.println("Please specify social network to target spam tool (default:Facebook):");
        System.out.println("1. Facebook");
        System.out.println("2. LinkedIn");
        String choice = scanner.nextLine();

        SocialNetwork network;
        if (choice.equals("2")) {
            network = new LinkedIn(createTestProfiles());
        }
        else {
            network = new Facebook(createTestProfiles());
        }

        SocialSpammer spammer = new SocialSpammer(network);
        spammer.sendSpamToFriends("anna.smith@bing.com",
                "Hey! This is Anna's friend Josh. Can you do me a favor and like this post [link]?");
        spammer.sendSpamToCoworkers("anna.smith@bing.com",
                "Hey! This is Anna's boss Jason. Anna told me you would be interested in [link].");
    }

    public static List<Profile> createTestProfiles() {
        List<Profile> data = new ArrayList<Profile>();
        data.add(new Profile("anna.smith@bing.com", "Anna Smith", "friends:mad_max@ya.com", "friends:catwoman@yahoo.com", "coworkers:sam@amazon.com"));
        data.add(new Profile("mad_max@ya.com", "Maximilian", "friends:anna.smith@bing.com", "coworkers:sam@amazon.com"));
        data.add(new Profile("bill@microsoft.eu", "Billie", "coworkers:avanger@ukr.net"));
        data.add(new Profile("avanger@ukr.net", "John Day", "coworkers:bill@microsoft.eu"));
        data.add(new Profile("sam@amazon.com", "Sam Kitting", "coworkers:anna.smith@bing.com", "coworkers:mad_max@ya.com", "friends:catwoman@yahoo.com"));
        data.add(new Profile("catwoman@yahoo.com", "Liza", "friends:anna.smith@bing.com", "friends:sam@amazon.com"));
        return data;
    }
}

Please specify social network to target spam tool (default:Facebook):
1. Facebook
2. LinkedIn
> 1

Iterating over friends...

Facebook: Loading 'friends' list of 'anna.smith@bing.com' over the network...
Facebook: Loading profile 'mad_max@ya.com' over the network...
Sent message to: 'mad_max@ya.com'. Message body: 'Hey! This is Anna's friend Josh. Can you do me a favor and like this post [link]?'
Facebook: Loading profile 'catwoman@yahoo.com' over the network...
Sent message to: 'catwoman@yahoo.com'. Message body: 'Hey! This is Anna's friend Josh. Can you do me a favor and like this post [link]?'

Iterating over coworkers...

Facebook: Loading 'coworkers' list of 'anna.smith@bing.com' over the network...
Facebook: Loading profile 'sam@amazon.com' over the network...
Sent message to: 'sam@amazon.com'. Message body: 'Hey! This is Anna's boss Jason. Anna told me you would be interested in [link].'
```

### csharp

```csharp
using System;
using System.Collections;
using System.Collections.Generic;

namespace RefactoringGuru.DesignPatterns.Iterator.Conceptual
{
    abstract class Iterator : IEnumerator
    {
        object IEnumerator.Current => Current();

        // يُعيد مفتاح العنصر الحالي
        public abstract int Key();
		
        // يُعيد العنصر الحالي
        public abstract object Current();
		
        // الانتقال إلى العنصر التالي
        public abstract bool MoveNext();
		
        // يُعيد المُكرِّر إلى العنصر الأول
        public abstract void Reset();
    }

    abstract class IteratorAggregate : IEnumerable
    {
        // يُعيد مُكرِّراً أو IteratorAggregate آخر للكائن
        // المُنفِّذ.
        public abstract IEnumerator GetEnumerator();
    }

    // تُنفِّذ المُكرِّرات المُحدَّدة خوارزميات اجتياز متنوعة. هذه الفئات
    // تخزن موضع الاجتياز الحالي في جميع الأوقات.
    class AlphabeticalOrderIterator : Iterator
    {
        private WordsCollection _collection;
		
        // Stores the current traversal position. An iterator may have a lot of
        // other fields for storing iteration state, especially when it is
        // supposed to work with a particular kind of collection.
        private int _position = -1;
		
        private bool _reverse = false;

        public AlphabeticalOrderIterator(WordsCollection collection, bool reverse = false)
        {
            this._collection = collection;
            this._reverse = reverse;

            if (reverse)
            {
                this._position = collection.getItems().Count;
            }
        }
		
        public override object Current()
        {
            return this._collection.getItems()[_position];
        }

        public override int Key()
        {
            return this._position;
        }
		
        public override bool MoveNext()
        {
            int updatedPosition = this._position + (this._reverse ? -1 : 1);

            if (updatedPosition >= 0 && updatedPosition < this._collection.getItems().Count)
            {
                this._position = updatedPosition;
                return true;
            }
            else
            {
                return false;
            }
        }
		
        public override void Reset()
        {
            this._position = this._reverse ? this._collection.getItems().Count - 1 : 0;
        }
    }

    // توفر المجموعات المُحدَّدة طريقة أو أكثر لاسترجاع
    // نسخ جديدة من المُكرِّر متوافقة مع فئة المجموعة.
    class WordsCollection : IteratorAggregate
    {
        List<string> _collection = new List<string>();
		
        bool _direction = false;
        
        public void ReverseDirection()
        {
            _direction = !_direction;
        }
		
        public List<string> getItems()
        {
            return _collection;
        }
		
        public void AddItem(string item)
        {
            this._collection.Add(item);
        }
		
        public override IEnumerator GetEnumerator()
        {
            return new AlphabeticalOrderIterator(this, _direction);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            // قد يعرف كود العميل أو لا يعرف عن المُكرِّر المُحدَّد
            // أو فئات المجموعة، بحسب مستوى الإخفاء الذي
            // تريد الاحتفاظ به في برنامجك.
            var collection = new WordsCollection();
            collection.AddItem("First");
            collection.AddItem("Second");
            collection.AddItem("Third");

            Console.WriteLine("Straight traversal:");

            foreach (var element in collection)
            {
                Console.WriteLine(element);
            }

            Console.WriteLine("\nReverse traversal:");

            collection.ReverseDirection();

            foreach (var element in collection)
            {
                Console.WriteLine(element);
            }
        }
    }
}

Straight traversal:
First
Second
Third

Reverse traversal:
Third
Second
First
```

### cpp

```cpp
/**
 * نمط تصميم المُكرِّر
 *
 * الغرض: يتيح لك اجتياز عناصر مجموعة دون الكشف عن تمثيلها الداخلي
 * (قائمة، مكدس، شجرة، إلخ).
 */

#include <iostream>
#include <string>
#include <vector>

/**
 * تمتلك C++ تنفيذها الخاص للمُكرِّر الذي يعمل مع
 * الحاويات العامة المختلفة المُعرَّفة في المكتبة القياسية.
 */

template <typename T, typename U>
class Iterator {
 public:
  typedef typename std::vector<T>::iterator iter_type;
  Iterator(U *p_data, bool reverse = false) : m_p_data_(p_data) {
    m_it_ = m_p_data_->m_data_.begin();
  }

  void First() {
    m_it_ = m_p_data_->m_data_.begin();
  }

  void Next() {
    m_it_++;
  }

  bool IsDone() {
    return (m_it_ == m_p_data_->m_data_.end());
  }

  iter_type Current() {
    return m_it_;
  }

 private:
  U *m_p_data_;
  iter_type m_it_;
};

/**
 * توفر المجموعات/الحاويات العامة طريقة أو أكثر لاسترجاع
 * نسخ جديدة من المُكرِّر متوافقة مع فئة المجموعة.
 */

template <class T>
class Container {
  friend class Iterator<T, Container>;

 public:
  void Add(T a) {
    m_data_.push_back(a);
  }

  Iterator<T, Container> *CreateIterator() {
    return new Iterator<T, Container>(this);
  }

 private:
  std::vector<T> m_data_;
};

class Data {
 public:
  Data(int a = 0) : m_data_(a) {}

  void set_data(int a) {
    m_data_ = a;
  }

  int data() {
    return m_data_;
  }

 private:
  int m_data_;
};

/**
 * قد يعرف كود العميل أو لا يعرف عن المُكرِّر المُحدَّد أو فئات المجموعة،
 * في هذا التنفيذ الحاوية عامة لذا يمكن استخدامها
 * مع int أو مع فئة مخصصة.
 */
void ClientCode() {
  std::cout << "________________Iterator with int______________________________________" << std::endl;
  Container<int> cont;

  for (int i = 0; i < 10; i++) {
    cont.Add(i);
  }

  Iterator<int, Container<int>> *it = cont.CreateIterator();
  for (it->First(); !it->IsDone(); it->Next()) {
    std::cout << *it->Current() << std::endl;
  }

  Container<Data> cont2;
  Data a(100), b(1000), c(10000);
  cont2.Add(a);
  cont2.Add(b);
  cont2.Add(c);

  std::cout << "________________Iterator with custom Class______________________________" << std::endl;
  Iterator<Data, Container<Data>> *it2 = cont2.CreateIterator();
  for (it2->First(); !it2->IsDone(); it2->Next()) {
    std::cout << it2->Current()->data() << std::endl;
  }
  delete it;
  delete it2;
}

int main() {
  ClientCode();
  return 0;
}

________________Iterator with int______________________________________
0
1
2
3
4
5
6
7
8
9
________________Iterator with custom Class______________________________
100
1000
10000
```

### go

```go
package main

type Collection interface {
	createIterator() Iterator
}

package main

type UserCollection struct {
	users []*User
}

func (u *UserCollection) createIterator() Iterator {
	return &UserIterator{
		users: u.users,
	}
}

package main

type Iterator interface {
	hasNext() bool
	getNext() *User
}

package main

type UserIterator struct {
	index int
	users []*User
}

func (u *UserIterator) hasNext() bool {
	if u.index < len(u.users) {
		return true
	}
	return false

}
func (u *UserIterator) getNext() *User {
	if u.hasNext() {
		user := u.users[u.index]
		u.index++
		return user
	}
	return nil
}

package main

type User struct {
	name string
	age  int
}

package main

import "fmt"

func main() {

	user1 := &User{
		name: "a",
		age:  30,
	}
	user2 := &User{
		name: "b",
		age:  20,
	}

	userCollection := &UserCollection{
		users: []*User{user1, user2},
	}

	iterator := userCollection.createIterator()

	for iterator.hasNext() {
		user := iterator.getNext()
		fmt.Printf("User is %+v\n", user)
	}
}

User is &{name:a age:30}
User is &{name:b age:20}
```

### php

```php
<?php

namespace RefactoringGuru\Iterator\Conceptual;

/**
 * تُنفِّذ المُكرِّرات المُحدَّدة خوارزميات اجتياز متنوعة. هذه الفئات
 * تخزن موضع الاجتياز الحالي في جميع الأوقات.
 */
class AlphabeticalOrderIterator implements \Iterator
{
    /**
     * @var WordsCollection
     */
    private $collection;

    /**
     * @var int يخزن موضع الاجتياز الحالي. قد يحتوي المُكرِّر على
     * الكثير من الحقول الأخرى لتخزين حالة التكرار، خاصةً عندما يُفترض
     * أن يعمل مع نوع معين من المجموعات.
     */
    private $position = 0;

    /**
     * @var bool يشير هذا المتغير إلى اتجاه الاجتياز.
     */
    private $reverse = false;

    public function __construct($collection, $reverse = false)
    {
        $this->collection = $collection;
        $this->reverse = $reverse;
    }

    public function rewind()
    {
        $this->position = $this->reverse ?
            count($this->collection->getItems()) - 1 : 0;
    }

    public function current()
    {
        return $this->collection->getItems()[$this->position];
    }

    public function key()
    {
        return $this->position;
    }

    public function next()
    {
        $this->position = $this->position + ($this->reverse ? -1 : 1);
    }

    public function valid()
    {
        return isset($this->collection->getItems()[$this->position]);
    }
}

/**
 * توفر المجموعات المُحدَّدة طريقة أو أكثر لاسترجاع
 * نسخ جديدة من المُكرِّر متوافقة مع فئة المجموعة.
 */
class WordsCollection implements \IteratorAggregate
{
    private $items = [];

    public function getItems()
    {
        return $this->items;
    }

    public function addItem($item)
    {
        $this->items[] = $item;
    }

    public function getIterator(): Iterator
    {
        return new AlphabeticalOrderIterator($this);
    }

    public function getReverseIterator(): Iterator
    {
        return new AlphabeticalOrderIterator($this, true);
    }
}

/**
 * قد يعرف كود العميل أو لا يعرف عن المُكرِّر المُحدَّد أو فئات المجموعة،
 * بحسب مستوى الإخفاء الذي تريد الاحتفاظ به في
 * برنامجك.
 */
$collection = new WordsCollection();
$collection->addItem("First");
$collection->addItem("Second");
$collection->addItem("Third");

echo "Straight traversal:\n";
foreach ($collection->getIterator() as $item) {
    echo $item . "\n";
}

echo "\n";
echo "Reverse traversal:\n";
foreach ($collection->getReverseIterator() as $item) {
    echo $item . "\n";
}

Straight traversal:
First
Second
Third

Reverse traversal:
Third
Second
First

<?php

namespace RefactoringGuru\Iterator\RealWorld;

/**
 * مُكرِّر ملفات CSV.
 *
 * @author Josh Lockhart
 */
class CsvIterator implements \Iterator
{
    const ROW_SIZE = 4096;

    /**
     * المؤشر إلى ملف CSV.
     *
     * @var resource
     */
    protected $filePointer = null;

    /**
     * العنصر الحالي الذي يُعاد في كل تكرار.
     *
     * @var array
     */
    protected $currentElement = null;

    /**
     * عداد الصفوف.
     *
     * @var int
     */
    protected $rowCounter = null;

    /**
     * المحدِّد لملف CSV.
     *
     * @var string
     */
    protected $delimiter = null;

    /**
     * يحاول المُنشئ فتح ملف CSV. يُرمي استثناءً عند الفشل.
     *
     * @param string $file ملف CSV.
     * @param string $delimiter المحدِّد.
     *
     * @throws \Exception
     */
    public function __construct($file, $delimiter = ',')
    {
        try {
            $this->filePointer = fopen($file, 'rb');
            $this->delimiter = $delimiter;
        } catch (\Exception $e) {
            throw new \Exception('The file "' . $file . '" cannot be read.');
        }
    }

    /**
     * تُعيد هذه الطريقة تعيين مؤشر الملف.
     */
    public function rewind(): void
    {
        $this->rowCounter = 0;
        rewind($this->filePointer);
        // قراءة الصف الأول للتهيئة
        $this->currentElement = fgetcsv($this->filePointer, self::ROW_SIZE, $this->delimiter);
    }

    /**
     * تُعيد هذه الطريقة صف CSV الحالي كمصفوفة ثنائية الأبعاد.
     *
     * @return array صف CSV الحالي كمصفوفة ثنائية الأبعاد.
     */
    public function current(): array
    {
        return $this->currentElement ?: [];
    }

    /**
     * تُعيد هذه الطريقة رقم الصف الحالي.
     *
     * @return int رقم الصف الحالي.
     */
    public function key(): int
    {
        return $this->rowCounter;
    }

    /**
     * تنتقل هذه الطريقة إلى العنصر التالي.
     */
    public function next(): void
    {
        if (is_resource($this->filePointer)) {
            $this->currentElement = fgetcsv($this->filePointer, self::ROW_SIZE, $this->delimiter);
            $this->rowCounter++;
        }
    }

    /**
     * تتحقق هذه الطريقة مما إذا كان الموضع الحالي صالحاً.
     *
     * @return bool ما إذا كان الموضع الحالي صالحاً.
     */
    public function valid(): bool
    {
        if ($this->currentElement === false) {
            if (is_resource($this->filePointer)) {
                fclose($this->filePointer);
            }

            return false;
        }

        return is_resource($this->filePointer);
    }
}

/**
 * كود العميل.
 */
$csv = new CsvIterator(__DIR__ . '/cats.csv');

foreach ($csv as $key => $row) {
    print_r($row);
}

Array
(
    [0] => Name
    [1] => Age
    [2] => Owner
    [3] => Breed
    [4] => Image
    [5] => Color
    [6] => Texture
    [7] => Fur
    [8] => Size
)
Array
(
    [0] => Steve
    [1] => 3
    [2] => Alexander Shvets
    [3] => Bengal
    [4] => /cats/bengal.jpg
    [5] => Brown
    [6] => Stripes
    [7] => Short
    [8] => Medium
)
Array
(
    [0] => Siri
    [1] => 2
    [2] => Alexander Shvets
    [3] => Domestic short-haired
    [4] => /cats/domestic-sh.jpg
    [5] => Black
    [6] => Solid
    [7] => Medium
    [8] => Medium
)
Array
(
    [0] => Fluffy
    [1] => 5
    [2] => John Smith
    [3] => Maine Coon
    [4] => /cats/Maine-Coon.jpg
    [5] => Gray
    [6] => Stripes
    [7] => Long
    [8] => Large
)
```

### python

```python
from __future__ import annotations
from collections.abc import Iterable, Iterator
from typing import Any


"""
لإنشاء مُكرِّر في Python، هناك فئتان مجردتان من الوحدة
المدمجة `collections` - Iterable وIterator. نحتاج إلى تنفيذ
الطريقة `__iter__()` في الكائن المُكرَّر (المجموعة)، والطريقة `__next__()`
في المُكرِّر.
"""


class AlphabeticalOrderIterator(Iterator):
    """
    تُنفِّذ المُكرِّرات المُحدَّدة خوارزميات اجتياز متنوعة. هذه الفئات
    تخزن موضع الاجتياز الحالي في جميع الأوقات.
    """

    """
    تخزن خاصية `_position` موضع الاجتياز الحالي. قد يحتوي المُكرِّر
    على الكثير من الحقول الأخرى لتخزين حالة التكرار، خاصةً عندما يُفترض
    أن يعمل مع نوع معين من المجموعات.
    """
    _position: int = None

    """
    تشير هذه الخاصية إلى اتجاه الاجتياز.
    """
    _reverse: bool = False

    def __init__(self, collection: WordsCollection, reverse: bool = False) -> None:
        self._collection = collection
        self._reverse = reverse
        self._sorted_items = None  # Will be set on first __next__ call
        self._position = 0

    def __next__(self) -> Any:
        """
        تحسين: يحدث الفرز فقط عند طلب العنصر الأول فعلياً.
        """
        if self._sorted_items is None:
            self._sorted_items = sorted(self._collection._collection)
            if self._reverse:
                self._sorted_items = list(reversed(self._sorted_items))

        """
        يجب أن تُعيد الطريقة __next__() العنصر التالي في التسلسل. عند
        الوصول إلى النهاية، وفي الاستدعاءات اللاحقة، يجب أن تُرمي StopIteration.
        """
        if self._position >= len(self._sorted_items):
            raise StopIteration()
        value = self._sorted_items[self._position]
        self._position += 1
        return value


class WordsCollection(Iterable):
    """
    توفر المجموعات المُحدَّدة طريقة أو أكثر لاسترجاع
    نسخ جديدة من المُكرِّر متوافقة مع فئة المجموعة.
    """

    def __init__(self, collection: list[Any] | None = None) -> None:
        self._collection = collection or []


    def __getitem__(self, index: int) -> Any:
        return self._collection[index]

    def __iter__(self) -> AlphabeticalOrderIterator:
        """
        تُعيد الطريقة __iter__() كائن المُكرِّر نفسه، بشكل افتراضي
        نُعيد المُكرِّر بترتيب تصاعدي.
        """
        return AlphabeticalOrderIterator(self)

    def get_reverse_iterator(self) -> AlphabeticalOrderIterator:
        return AlphabeticalOrderIterator(self, True)

    def add_item(self, item: Any) -> None:
        self._collection.append(item)


if __name__ == "__main__":
    # قد يعرف كود العميل أو لا يعرف عن المُكرِّر المُحدَّد أو
    # فئات المجموعة، بحسب مستوى الإخفاء الذي تريد الاحتفاظ به
    # في برنامجك.
    collection = WordsCollection()
    collection.add_item("B")
    collection.add_item("A")
    collection.add_item("C")

    print("Straight traversal:")
    print("\n".join(collection))
    print("")

    print("Reverse traversal:")
    print("\n".join(collection.get_reverse_iterator()), end="")

Straight traversal:
A
B
C

Reverse traversal:
C
B
A
```

### ruby

```ruby
class AlphabeticalOrderIterator
  # في Ruby، توفر mixin Enumerable للفئات عدة طرق للاجتياز
  # والبحث، وإمكانية الفرز. يجب أن توفر الفئة
  # طريقة each تُنتج أعضاء المجموعة المتتالية.
  include Enumerable

  # تشير هذه الخاصية إلى اتجاه الاجتياز.
  attr_accessor :reverse
  private :reverse

  # @return [Array]
  attr_accessor :collection
  private :collection

  # @param [Array] collection
  # @param [Boolean] reverse
  def initialize(collection, reverse: false)
    @collection = collection
    @reverse = reverse
  end

  def each(&block)
    return @collection.reverse.each(&block) if reverse

    @collection.each(&block)
  end
end

class WordsCollection
  # @return [Array]
  attr_accessor :collection
  private :collection

  def initialize(collection = [])
    @collection = collection
  end

  # تُعيد طريقة `iterator` كائن المُكرِّر نفسه، بشكل افتراضي
  # نُعيد المُكرِّر بترتيب تصاعدي.
  def iterator
    AlphabeticalOrderIterator.new(@collection)
  end

  # @return [AlphabeticalOrderIterator]
  def reverse_iterator
    AlphabeticalOrderIterator.new(@collection, reverse: true)
  end

  # @param [String] item
  def add_item(item)
    @collection << item
  end
end

# قد يعرف كود العميل أو لا يعرف عن المُكرِّر المُحدَّد أو فئات المجموعة،
# بحسب مستوى الإخفاء الذي تريد الاحتفاظ به في برنامجك.
collection = WordsCollection.new
collection.add_item('First')
collection.add_item('Second')
collection.add_item('Third')

puts 'Straight traversal:'
collection.iterator.each { |item| puts item }
puts "\n"

puts 'Reverse traversal:'
collection.reverse_iterator.each { |item| puts item }

Straight traversal:
First
Second
Third

Reverse traversal:
Third
Second
First
```

### rust

```rust
let array = &[1, 2, 3];
let iterator = array.iter();

// الاجتياز عبر كل عنصر في المصفوفة.
iterator.for_each(|e| print!("{}, ", e));

let users = UserCollection::new();
let mut iterator = users.iter();

iterator.next();

impl Iterator for UserIterator<'_> {
    fn next(&mut self) -> Option<Self::Item>;
}

pub struct UserCollection {
    users: [&'static str; 3],
}

/// تحتوي المجموعة المخصصة على مصفوفة مستخدمين عشوائية في الخلفية.
impl UserCollection {
    /// تُعيد مجموعة مستخدمين مخصصة.
    pub fn new() -> Self {
        Self {
            users: ["Alice", "Bob", "Carl"],
        }
    }

    /// تُعيد مُكرِّراً على مجموعة مستخدمين.
    ///
    /// قد يختلف اسم الطريقة، غير أن `iter` تُستخدَم كمعيار فعلي
    /// في اصطلاح تسمية Rust.
    pub fn iter(&self) -> UserIterator {
        UserIterator {
            index: 0,
            user_collection: self,
        }
    }
}

/// يتيح UserIterator الاجتياز التسلسلي عبر مجموعة مستخدمين معقدة
/// دون الكشف عن تفاصيلها الداخلية.
pub struct UserIterator<'a> {
    index: usize,
    user_collection: &'a UserCollection,
}

/// `Iterator` هي واجهة قياسية للتعامل مع المُكرِّرات
/// من مكتبة Rust القياسية.
impl Iterator for UserIterator<'_> {
    type Item = &'static str;

    /// طريقة `next` هي الطريقة الوحيدة في سمة `Iterator` التي يجب
    /// تنفيذها. تُتيح الوصول إلى مجموعة واسعة من الطرق القياسية،
    /// مثل `fold` و`map` و`for_each`.
    fn next(&mut self) -> Option<Self::Item> {
        if self.index < self.user_collection.users.len() {
            let user = Some(self.user_collection.users[self.index]);
            self.index += 1;
            return user;
        }

        None
    }
}

use crate::users::UserCollection;

mod users;

fn main() {
    print!("Iterators are widely used in the standard library: ");

    let array = &[1, 2, 3];
    let iterator = array.iter();

    // الاجتياز عبر كل عنصر في المصفوفة.
    iterator.for_each(|e| print!("{} ", e));

    println!("\n\nLet's test our own iterator.\n");

    let users = UserCollection::new();
    let mut iterator = users.iter();

    println!("1nd element: {:?}", iterator.next());
    println!("2nd element: {:?}", iterator.next());
    println!("3rd element: {:?}", iterator.next());
    println!("4th element: {:?}", iterator.next());

    print!("\nAll elements in user collection: ");
    users.iter().for_each(|e| print!("{} ", e));

    println!();
}

Iterators are widely used in the standard library: 1 2 3

Let's test our own iterator.

1nd element: Some("Alice")
2nd element: Some("Bob")
3rd element: Some("Carl")
4th element: None


All elements in user collection: Alice Bob Carl
```

### swift

```swift
import XCTest

/// هذه مجموعة سنجتازها باستخدام مُكرِّر
/// يتوافق مع IteratorProtocol.
class WordsCollection {

    fileprivate lazy var items = [String]()

    func append(_ item: String) {
        self.items.append(item)
    }
}

extension WordsCollection: Sequence {

    func makeIterator() -> WordsIterator {
        return WordsIterator(self)
    }
}

/// تُنفِّذ المُكرِّرات المُحدَّدة خوارزميات اجتياز متنوعة. هذه الفئات
/// تخزن موضع الاجتياز الحالي في جميع الأوقات.
class WordsIterator: IteratorProtocol {

    private let collection: WordsCollection
    private var index = 0

    init(_ collection: WordsCollection) {
        self.collection = collection
    }

    func next() -> String? {
        defer { index += 1 }
        return index < collection.items.count ? collection.items[index] : nil
    }
}


/// هذه مجموعة أخرى سنوفر لها AnyIterator لاجتياز
/// عناصرها.
class NumbersCollection {

    fileprivate lazy var items = [Int]()

    func append(_ item: Int) {
        self.items.append(item)
    }
}

extension NumbersCollection: Sequence {

    func makeIterator() -> AnyIterator<Int> {
        var index = self.items.count - 1

        return AnyIterator {
            defer { index -= 1 }
            return index >= 0 ? self.items[index] : nil
        }
    }
}

/// العميل لا يعرف التمثيل الداخلي لتسلسل معين.
class Client {
    // ...
    static func clientCode<S: Sequence>(sequence: S) {
        for item in sequence {
            print(item)
        }
    }
    // ...
}

/// Let's see how it all works together.
class IteratorConceptual: XCTestCase {

    func testIteratorProtocol() {

        let words = WordsCollection()
        words.append("First")
        words.append("Second")
        words.append("Third")

        print("Straight traversal using IteratorProtocol:")
        Client.clientCode(sequence: words)
    }

    func testAnyIterator() {

        let numbers = NumbersCollection()
        numbers.append(1)
        numbers.append(2)
        numbers.append(3)

        print("\nReverse traversal using AnyIterator:")
        Client.clientCode(sequence: numbers)
    }
}

Straight traversal using IteratorProtocol:
First
Second
Third

Reverse traversal using AnyIterator:
3
2
1

import XCTest

class IteratorRealWorld: XCTestCase {

    func test() {

        let tree = Tree(1)
        tree.left = Tree(2)
        tree.right = Tree(3)

        print("Tree traversal: Inorder")
        clientCode(iterator: tree.iterator(.inOrder))

        print("\nTree traversal: Preorder")
        clientCode(iterator: tree.iterator(.preOrder))

        print("\nTree traversal: Postorder")
        clientCode(iterator: tree.iterator(.postOrder))
    }

    func clientCode<T>(iterator: AnyIterator<T>) {
        while case let item? = iterator.next() {
            print(item)
        }
    }
}

class Tree<T> {

    var value: T
    var left: Tree<T>?
    var right: Tree<T>?

    init(_ value: T) {
        self.value = value
    }

    typealias Block = (T) -> ()

    enum IterationType {
        case inOrder
        case preOrder
        case postOrder
    }

    func iterator(_ type: IterationType) -> AnyIterator<T> {
        var items = [T]()
        switch type {
        case .inOrder:
            inOrder { items.append($0) }
        case .preOrder:
            preOrder { items.append($0) }
        case .postOrder:
            postOrder { items.append($0) }
        }

        /// ملاحظة:
        /// يُستخدَم AnyIterator لإخفاء توقيع النوع لمُكرِّر
        /// داخلي.
        return AnyIterator(items.makeIterator())
    }

    private func inOrder(_ body: Block) {
        left?.inOrder(body)
        body(value)
        right?.inOrder(body)
    }

    private func preOrder(_ body: Block) {
        body(value)
        left?.preOrder(body)
        right?.preOrder(body)
    }

    private func postOrder(_ body: Block) {
        left?.postOrder(body)
        right?.postOrder(body)
        body(value)
    }
}

Tree traversal: Inorder
2
1
3

Tree traversal: Preorder
1
2
3

Tree traversal: Postorder
2
3
1
```

### typescript

```typescript
/**
 * نمط تصميم المُكرِّر
 *
 * الغرض: يتيح لك اجتياز عناصر مجموعة دون الكشف عن تمثيلها الداخلي
 * (قائمة، مكدس، شجرة، إلخ).
 */

interface Iterator<T> {
    // إرجاع العنصر الحالي.
    current(): T;

    // إرجاع العنصر الحالي والتقدم إلى العنصر التالي.
    next(): T;

    // إرجاع مفتاح العنصر الحالي.
    key(): number;

    // التحقق مما إذا كان الموضع الحالي صالحاً.
    valid(): boolean;

    // إعادة المُكرِّر إلى العنصر الأول.
    rewind(): void;
}

interface Aggregator {
    // استرجاع مُكرِّر خارجي.
    getIterator(): Iterator<string>;
}

/**
 * تُنفِّذ المُكرِّرات المُحدَّدة خوارزميات اجتياز متنوعة. هذه الفئات
 * تخزن موضع الاجتياز الحالي في جميع الأوقات.
 */

class AlphabeticalOrderIterator implements Iterator<string> {
    private collection: WordsCollection;

    /**
     * يخزن موضع الاجتياز الحالي. قد يحتوي المُكرِّر على العديد
     * من الحقول الأخرى لتخزين حالة التكرار، خاصةً عندما يُفترض
     * أن يعمل مع نوع معين من المجموعات.
     */
    private position: number = 0;

    /**
     * يشير هذا المتغير إلى اتجاه الاجتياز.
     */
    private reverse: boolean = false;

    constructor(collection: WordsCollection, reverse: boolean = false) {
        this.collection = collection;
        this.reverse = reverse;

        if (reverse) {
            this.position = collection.getCount() - 1;
        }
    }

    public rewind() {
        this.position = this.reverse ?
            this.collection.getCount() - 1 :
            0;
    }

    public current(): string {
        return this.collection.getItems()[this.position];
    }

    public key(): number {
        return this.position;
    }

    public next(): string {
        const item = this.collection.getItems()[this.position];
        this.position += this.reverse ? -1 : 1;
        return item;
    }

    public valid(): boolean {
        if (this.reverse) {
            return this.position >= 0;
        }

        return this.position < this.collection.getCount();
    }
}

/**
 * توفر المجموعات المُحدَّدة طريقة أو أكثر لاسترجاع
 * نسخ جديدة من المُكرِّر متوافقة مع فئة المجموعة.
 */
class WordsCollection implements Aggregator {
    private items: string[] = [];

    public getItems(): string[] {
        return this.items;
    }

    public getCount(): number {
        return this.items.length;
    }

    public addItem(item: string): void {
        this.items.push(item);
    }

    public getIterator(): Iterator<string> {
        return new AlphabeticalOrderIterator(this);
    }

    public getReverseIterator(): Iterator<string> {
        return new AlphabeticalOrderIterator(this, true);
    }
}

/**
 * قد يعرف كود العميل أو لا يعرف عن المُكرِّر المُحدَّد أو فئات المجموعة،
 * بحسب مستوى الإخفاء الذي تريد الاحتفاظ به في برنامجك.
 */
const collection = new WordsCollection();
collection.addItem('First');
collection.addItem('Second');
collection.addItem('Third');

const iterator = collection.getIterator();

console.log('Straight traversal:');
while (iterator.valid()) {
    console.log(iterator.next());
}

console.log('');
console.log('Reverse traversal:');
const reverseIterator = collection.getReverseIterator();
while (reverseIterator.valid()) {
    console.log(reverseIterator.next());
}

Straight traversal:
First
Second
Third

Reverse traversal:
Third
Second
First
```

