نمط المكرر
جزء من قسم البرمجة كائنية التوجه في رحلة Java على Coddy. الدرس 76 من 87.
يُعد Iterator Pattern نمط تصميم سلوكيًا يوفّر طريقة للوصول إلى عناصر مجموعة بالتتابع دون كشف بنيتها الأساسية. سواء كنت تعمل مع array أو قائمة مرتبطة أو شجرة، يمنحك iterator طريقة موحّدة لاجتياز العناصر.
يفصل النمط منطق الاجتياز عن المجموعة نفسها. ويتضمن مكوّنين رئيسيين: واجهة Iterator التي تحدد أساليب لاجتياز العناصر، وIterable (أو Aggregate) التي تنشئ مكررات لمجموعتها:
interface Iterator<T> {
boolean hasNext();
T next();
}
interface Container<T> {
Iterator<T> createIterator();
}
class BookShelf implements Container<String> {
private String[] books;
private int count = 0;
public BookShelf(int size) {
books = new String[size];
}
public void addBook(String book) {
books[count++] = book;
}
public Iterator<String> createIterator() {
return new BookIterator();
}
private class BookIterator implements Iterator<String> {
private int index = 0;
public boolean hasNext() {
return index < count;
}
public String next() {
return books[index++];
}
}
}يحافظ iterator على حالة الاجتياز الخاصة بـ its، مما يتيح لعدة كائنات iterator اجتياز المجموعة نفسها بشكل مستقل. يستخدم العملاء iterator من دون معرفة كيفية تخزين المجموعة لبياناتها:
BookShelf shelf = new BookShelf(3);
shelf.addBook("Design Patterns");
shelf.addBook("Clean Code");
Iterator<String> iterator = shelf.createIterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}تتبع الواجهتان المضمّنتان في Java، Iterable وIterator، هذا النمط الدقيق، ولهذا يمكنك استخدام حلقات for المحسّنة مع أي فئة تطبّق Iterable. يُعد نمط Iterator ضروريًا عندما تحتاج إلى توفير أساليب متعددة للتنقّل أو إخفاء الهياكل الداخلية المعقّدة عن كود العميل.
التحدي
سهللنُنشئ نظام قائمة تشغيل باستخدام نمط Iterator! ستنشئ قائمة تشغيل موسيقية تخزّن الأغاني وتوفّر مكرّرًا مخصّصًا للتنقّل بينها بالتسلسل، من دون كشف كيفية تخزين الأغاني داخليًا. هذه حالة استخدام مثالية لنمط Iterator، إذ تتيح للمستخدمين التنقّل في مجموعتك من خلال واجهة نظيفة وموحّدة.
ستنظّم كودك عبر أربعة ملفات:
Iterator.java: Define واجهةIterator<T>generic الخاصة بك مع طريقتين:hasNext()التي تُرجع قيمة boolean تشير إلى ما إذا كانت هناك عناصر أخرى، وnext()التي تُرجع العنصر التالي من النوع T.Playlist.java: Create فئة Aggregate التي holds أغانيك. يجب أن تخزّنPlaylistالأغاني في مصفوفة String ذات capacity ثابتة (يتم تمريرها إلى constructor) وتتتبّع عدد الأغاني التي تمت إضافتها. ضمّن طريقةaddSong(String song)لإضافة الأغاني إلى قائمة التشغيل.تحتاج Playlist إلى طريقة
createIterator()تُرجعIterator<String>. Implement ذلك من خلال إنشاء فئة inner خاصة تُسمّىPlaylistIteratorوتطبّق واجهة Iterator الخاصة بك. يحافظ هذا الـ iterator الداخلي على موضعindexالخاص به، ويتنقّل عبر مصفوفة الأغاني، مُرجعًا كل أغنية بالترتيب.Song.java: Create فئةSongبسيطة تغلّف عنوان أغنية. يجب أن تحتوي على constructor يستقبل العنوان (String)، وطريقةgetTitle()، وطريقةtoString()تُرجعPlaying: [title].Main.java: اجمع نظام iterator الخاص بك! ستتلقى input واحدًا: قائمة بعناوين الأغاني مفصولة بفواصل (على سبيل المثال:Bohemian Rhapsody,Stairway to Heaven,Hotel California).Create كائن Playlist بسعة 10 أغانٍ. حلّل input وأضف كل عنوان أغنية إلى قائمة التشغيل. ثم احصل على iterator من قائمة التشغيل واستخدمه للتنقّل عبر جميع الأغاني، مع طباعة كل أغنية مغلّفة داخل كائن Song (والذي سيظهر بالشكل
Playing: [title]).بعد iterating عبر جميع الأغاني، اطبع
Playlist complete!في سطر جديد.
ستتلقى input واحدًا: سلسلة مفصولة بفواصل من عناوين الأغاني.
على سبيل المثال، عند استخدام input Yesterday,Imagine,Let It Be، سيكون output الخاص بك:
Playing: Yesterday
Playing: Imagine
Playing: Let It Be
Playlist complete!لاحظ كيف تستخدم فئة Main الخاصة بك طريقتَي hasNext() وnext() الخاصتين بـ iterator للتنقّل عبر قائمة التشغيل من دون معرفة أي شيء عن بنية المصفوفة underlying. يغلّف iterator كل منطق التنقّل، ويحافظ على إخفاء التمثيل الداخلي للمجموعة عن كود العميل!
جرّب بنفسك
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String input = scanner.nextLine();
// TODO: إنشاء Playlist بسعة 10 أغاني
// TODO: تحليل المدخلات (المفصولة بفواصل) وإضافة عنوان كل أغنية إلى الـ playlist
// TODO: الحصول على iterator من الـ playlist باستخدام createIterator()
// TODO: استخدام الـ iterator للتنقل عبر جميع الأغاني
// لكل أغنية، قم بتغليفها في كائن Song واطبعها
// TODO: Print "Playlist complete!" after iterating through all songs
}
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
1أساسيات الـ OOP
الملفات الخارجيةمقدمة في الـ OOPالفئات (Classes) مقابل الكائنات (Objects)الكلمة المفتاحية thisالدوال (Methods)الحقول (Attributes)دالة البناء (Constructor)تعدد أشكال دالة البناء (Constructor Overloading)مراجعة - آلة حاسبة بسيطة4الوراثة
الوراثة الأساسية (extends)الكلمة المفتاحية superإعادة تعريف الدوال (@Override)تسلسل المنشئات (Constructor Chaining)كلاس Objectالوراثة الأحادية ومتعددة المستوياتلماذا لا توجد وراثة متعددة للكلاساتمراجعة - هيكلية الموظفين7الدوال الخاصة وفئة Object
دالة toString()equals() و hashCode()دالة clone()compareTo() و Comparableواجهة Comparatorمراجعة - الترتيب المخصص2محددات الوصول والتغليف
نظرة عامة على مستويات الوصولدوال Getter و Setterإخفاء البياناتالكلمة المفتاحية finalمراجعة - مدير الحساب البنكي5تعدد الأشكال (Polymorphism)
أساسيات الـ Method Overloadingالـ Method Overriding (في وقت التشغيل)الـ Upcasting والـ Downcastingمعامل الـ instanceofالفئات والدوال المجردة (Abstract)مراجعة - حاسبة الأشكال8مفاهيم OOP المتقدمة
الـ Composition مقابل الـ Inheritanceالـ Aggregation مقابل الـ Compositionالفئات الداخلية والمتداخلة والمجهولة (Inner, Nested & Anonymous)الـ Enums ودوالهاالـ Records (Java 16+)الـ Sealed Classes (Java 17+)11أنماط التصميم - الجزء الأول
مقدمة في أنماط التصميمنمط Singletonنمط Factoryنمط Builderنمط Observerنمط Strategy3خصائص الفئة والعضو الساكن
المتغيرات الخاصة بالكائن مقابل المتغيرات الساكنةالدوال الساكنةالكتل البرمجية الساكنةالثوابت (static final)ملخص - العداد والأدوات المساعدة6الواجهات (Interfaces) والأصناف المجردة (Abstract Classes)
مقدمة في الواجهات (Interfaces)تنفيذ الواجهات (Interfaces)تنفيذ واجهات متعددةالـ Default و Static في الواجهاتالأصناف المجردة مقابل الواجهاتالواجهات الوظيفية (Functional Interfaces)مراجعة - نظام الدفع9الأنواع العامة (Generics)
مقدمة في الأنواع العامةالأصناف العامة (Generic Classes)الدوال العامة (Generic Methods)معاملات الأنواع المقيدةالرموز البديلة (?, extends, super)مراجعة - الحاويات العامة12أنماط التصميم - الجزء الثاني
نمط الأمرنمط المحولنمط المزيننمط طريقة القالبنمط الحالةنمط التركيبنمط المكررتدرّب بنفسك: مترجم Java عبر الإنترنت