يعد "التكرار" أحد أنماط التصميم التي لا يلاحظها المبرمجون في أغلب الأحيان ، لأن تنفيذها ، كقاعدة عامة ، يتم تضمينه مباشرةً في الأدوات القياسية للغة البرمجة. ومع ذلك ، يعد هذا أيضًا أحد الأنماط السلوكية الموضحة في 
كتاب "Gang of Four" ، و "GoF" ، و "أنماط التصميم: عناصر من البرنامج الموجه لإعادة الاستخدام" ، وفهمها لا يؤلم الجهاز الخاص به ، وأحيانًا يمكن أن يساعد في شيء ما.
"التكرار" هو وسيلة للوصول المتسلسل إلى جميع عناصر كائن مركب (على وجه الخصوص ، أنواع الحاويات ، مثل مجموعة أو مجموعة).أدوات اللغة القياسية
إنشاء نوع من 
الصفيف :
let numbersArray = [0, 1, 2] 
... ثم "المشي" من خلال ذلك في 
دورة :
 for number in numbersArray { print(number) } 
... يبدو وكأنه إجراء طبيعي للغاية ، خاصة بالنسبة للغات البرمجة الحديثة مثل 
سويفت . ومع ذلك ، وراء الكواليس من هذا الإجراء البسيط هو رمز ينفذ مبادئ نمط التكرار.
في "Swift" ، من أجل التمكن من "تكرار" المتغير باستخدام التكرار ، يجب أن يقوم النوع المتغير بتطبيق 
بروتوكول Sequence . من بين أشياء أخرى ، يتطلب هذا البروتوكول من النوع أن يكون لديه 
Iterator associatedtype ، والذي بدوره يجب أن ينفذ متطلبات بروتوكول 
IteratorProtocol ، وكذلك 
makeIterator() method factory factory الذي يعرض "محدد" محدد لهذا النوع:
 protocol Sequence { associatedtype Iterator : IteratorProtocol func makeIterator() -> Self.Iterator  
يحتوي بروتوكول 
IteratorProtocol ، بدوره ، على طريقة واحدة فقط - 
next() ، والتي تُرجع العنصر التالي في التسلسل:
 protocol IteratorProtocol { associatedtype Element mutating func next() -> Self.Element? } 
يبدو مثل "الكثير من التعليمات البرمجية المعقدة" ، لكنه في الواقع ليس كذلك. أدناه سوف نرى هذا.
يقوم نوع 
Array بتنفيذ بروتوكول 
Sequence (ولكن ليس بشكل مباشر ، ولكن من خلال سلسلة 
ميراث البروتوكول : يرث 
MutableCollection متطلبات 
Collection ، والأخير يرث متطلبات 
Sequence ) ، لذلك يمكن مثيلاته ، على وجه الخصوص ، "التكرار" باستخدام 
for -cycles.
أنواع مخصصة
ما الذي يجب القيام به لتتمكن من تكرار نوعك الخاص؟ كما يحدث في كثير من الأحيان ، فمن الأسهل لإظهار مثال.
افترض أن هناك نوعًا يمثل رفًا للكتب يخزن مجموعة معينة من مثيلات الفصل ، والذي بدوره يمثل كتابًا:
 struct Book { let author: String let title: String } struct Shelf { var books: [Book] } 
لتكون قادرًا على "تكرار" مثيل لفئة 
Shelf ، يجب أن تفي هذه الفئة بمتطلبات بروتوكول 
Sequence . على سبيل المثال ، سيكون تطبيق أسلوب 
makeIterator() كافياً فقط ، خاصة وأن متطلبات البروتوكول الأخرى لها 
تطبيقات افتراضية . يجب أن تقوم هذه الطريقة بإرجاع مثيل لنوع يقوم بتنفيذ بروتوكول 
IteratorProtocol . لحسن الحظ ، في حالة سويفت ، هذا رمز بسيط للغاية:
 struct ShelfIterator: IteratorProtocol { private var books: [Book] init(books: [Book]) { self.books = books } mutating func next() -> Book? {  
تم الإعلان عن تغيير الطريقة 
next() الخاصة بنوع 
ShelfIterator ، لأن مثيل الكتابة يجب أن يخزن بطريقة ما الحالة المقابلة للتكرار الحالي:
 mutating func next() -> Book? { defer { if !books.isEmpty { books.removeFirst() } } return books.first } 
يعرض خيار التطبيق هذا دائمًا العنصر الأول في التسلسل ، أو 
nil إذا كان التسلسل فارغًا. 
defer "لف" كتلة التأجيل برمز لتغيير المجموعة التكرارية ، مما يزيل عنصر آخر خطوة تكرارية فور عودة الطريقة.
مثال للاستخدام:
 let book1 = Book(author: ". ", title: "") let book2 = Book(author: ". ", title: " ") let book3 = Book(author: ". ", title: " ") let shelf = Shelf(books: [book1, book2, book3]) for book in shelf { print("\(book.author) – \(book.title)") }  
بسبب تستند جميع الأنواع المستخدمة (بما في ذلك 
Shelf الأساسي 
Shelf ) إلى 
دلالات القيم (على عكس المراجع) ، فلا داعي للقلق بشأن قيمة المتغير الأصلي الذي يتم تغييره أثناء التكرار. عند التعامل مع الأنواع استنادًا إلى دلالات الارتباط ، يجب أن تؤخذ هذه النقطة في الاعتبار وتؤخذ في الاعتبار عند إنشاء برامج التكرار الخاصة بك.
وظائف الكلاسيكية
يمكن لـ "التكرار" الكلاسيكي الموصوف في كتاب "Gang of of Four" ، بالإضافة إلى إرجاع العنصر التالي للتسلسل القابل للتكرار ، في أي وقت أيضًا إرجاع العنصر الحالي في عملية التكرار ، العنصر الأول في التسلسل التكراري وقيمة "العلم" الذي يشير إلى ما إذا كان لا يزال هناك العناصر في تسلسل مكرر نسبة إلى خطوة التكرار الحالية.
بالطبع ، سيكون من السهل الإعلان عن بروتوكول وبالتالي توسيع قدرات 
IteratorProtocol القياسية:
 protocol ClassicIteratorProtocol: IteratorProtocol { var currentItem: Element? { get } var first: Element? { get } var isDone: Bool { get } } 
يتم إرجاع العناصر الأولى والحالية اختياري منذ قد يكون تسلسل المصدر فارغًا.
خيار التنفيذ البسيط:
 struct ShelfIterator: ClassicIteratorProtocol { var currentItem: Book? = nil var first: Book? var isDone: Bool = false private var books: [Book] init(books: [Book]) { self.books = books first = books.first currentItem = books.first } mutating func next() -> Book? { currentItem = books.first books.removeFirst() isDone = books.isEmpty return books.first } } 
في الوصف الأصلي للنمط ، يغير الأسلوب 
next() الحالة الداخلية للتكرار للانتقال إلى العنصر التالي ويكون من النوع 
Void ، ويتم إرجاع العنصر الحالي بواسطة الأسلوب 
currentElement() . في بروتوكول 
IteratorProtocol ، تكون هاتان الوظيفتان كما لو تم دمجهما في واحدة.
الحاجة إلى الطريقة 
first() مشكوك فيها أيضًا ، لأن لا يغير التكرار التسلسل الأصلي ، ولدينا دائمًا فرصة الوصول إلى العنصر الأول (إن وجد ، بالطبع).
ونظرًا لأن الطريقة 
next() تُرجع 
nil عند انتهاء التكرار ، فإن الطريقة 
isDone() أيضًا تصبح عديمة الفائدة.
ومع ذلك ، للأغراض الأكاديمية ، من الممكن تمامًا التوصل إلى وظيفة يمكنها استخدام الوظيفة الكاملة:
 func printShelf(with iterator: inout ShelfIterator) { var bookIndex = 0 while !iterator.isDone { bookIndex += 1 print("\(bookIndex). \(iterator.currentItem!.author) – \(iterator.currentItem!.title)") _ = iterator.next() } } var iterator = ShelfIterator(books: shelf.books) printShelf(with: &iterator)  
المعلنة 
iterator يتم الإعلان عنها بسبب تتغير حالتها الداخلية أثناء تنفيذ الوظيفة. وعندما يتم استدعاء الوظيفة ، يتم نقل مثيل التكرار ليس مباشرة من خلال قيمته الخاصة ، ولكن حسب المرجع.
لا يتم استخدام نتيجة استدعاء الأسلوب 
next() ، محاكاة غياب القيمة المرجعة لتطبيق كتاب مدرسي.
بدلا من الاستنتاج
يبدو أن هذا هو كل ما أردت قوله هذه المرة. كل رمز جميل ومتعمد كتابته!
مقالاتي الأخرى عن أنماط التصميم: