JavaRush /جاوا بلاگ /Random-UR /تکرار کرنے والا پیٹرن

تکرار کرنے والا پیٹرن

گروپ میں شائع ہوا۔
آج ہم بات کریں گے کہ جاوا میں Iterator کیا ہے اور اس کی ضرورت کیوں ہے۔
تکرار کرنے والا پیٹرن - 1
جیسا کہ آپ شاید پہلے ہی جانتے ہوں گے، جاوا میں ایک شاندار کلیکشن انٹرفیس ہے جو Iterator انٹرفیس کو نافذ کرتا ہے۔ مجھے ابھی ایک ریزرویشن کرنے دو: ایٹریٹر انٹرفیس کو جاوا میں ایٹریٹر پیٹرن کے ساتھ الجھن میں نہیں ہونا چاہئے! اور واضح کرنے کے لیے، آئیے پہلے انٹرفیس کو دیکھیں۔
لفظی طور پر، "Iterator" کا ترجمہ "بروٹ فورس " کے طور پر کیا جا سکتا ہے ۔ یعنی، یہ ایک مخصوص ہستی ہے جو مجموعہ میں موجود تمام عناصر کے ذریعے اعادہ کر سکتی ہے۔ مزید برآں، یہ آپ کو جمع کرنے کے اندرونی ڈھانچے اور انتظامات میں دلچسپی کے بغیر ایسا کرنے کی اجازت دیتا ہے۔
آئیے ایک سیکنڈ کے لیے تصور کریں کہ جاوا میں کوئی تکرار کنندہ نہیں ہے۔ اس صورت میں، ہر ایک کو مجموعے کی بہت گہرائیوں میں غوطہ لگانا ہوگا اور صحیح معنوں میں سمجھنا ہوگا کہ کیا اور اس سے ArrayListمختلف ہے ۔ LinkedListHashSetTreeSet

وہ طریقے جو Iterator کو لاگو کرنا ہوں گے۔

boolean hasNext()— اگر اب بھی قابل تکرار آبجیکٹ (فی الحال ایک مجموعہ) میں قدریں باقی ہیں، تو طریقہ واپس آ جائے گا true، اگر مزید قدریں نہیں ہیں false۔ E next()- مجموعہ کا اگلا عنصر (آبجیکٹ) لوٹاتا ہے۔ اگر مزید عناصر نہیں ہیں (کوئی چیک نہیں تھا hasNext()، اور next()جب ہم مجموعہ کے اختتام پر پہنچے تو ہم نے فون کیا)، طریقہ پھینک دے گا NoSuchElementException۔ void remove()- اس عنصر کو ہٹا دے گا جو آخری بار کے ذریعہ حاصل کیا گیا تھا next()۔ طریقہ پھینک سکتا ہے:
  • UnsupportedOperationException، اگر یہ تکرار کرنے والا طریقہ کی حمایت نہیں کرتا ہے remove()(مثال کے طور پر صرف پڑھنے کے مجموعوں کی صورت میں)
  • IllegalStateException، اگر طریقہ next()ابھی تک کال نہیں کیا گیا ہے، یا اگر اسے remove()آخری کال کے بعد سے پہلے ہی کال کیا گیا ہے next()۔
لہذا، فہرست کے لئے تکرار کرنے والا سب سے عام نفاذ ہے۔ تکرار کرنے والا مجموعہ کے آغاز سے اس کے اختتام تک جاتا ہے: یہ دیکھتا ہے کہ آیا اگلا عنصر موجود ہے اور اگر کوئی ہے تو اسے واپس کرتا ہے۔ اس سادہ الگورتھم کی بنیاد پر ایک سائیکل بنایا گیا ہے for-each۔ اس کی توسیع ListIterator ہے۔ آئیے اضافی جاوا فہرست تکرار کرنے والے طریقوں کو دیکھیں۔ آپ شاید انہیں جانتے ہیں:
  • void add(E e)E- میں ایک عنصر داخل کرتا ہے ؛List
  • boolean hasPrevious()- trueاگر Listریورس تلاش کے دوران عناصر موجود ہوں تو واپس آجائے گا۔
  • int nextIndex()- اگلے عنصر کا انڈیکس واپس کرے گا۔
  • E previous()- پچھلی شیٹ عنصر واپس کرے گا؛
  • int previousIndex()- پچھلے عنصر کا اشاریہ واپس کرے گا۔
  • void set(E e)- آخری کال کے ذریعے لوٹائے گئے عنصر کو next()یا previous()عنصر سے بدل دے گا e۔
آئیے ایک چھوٹی سی مثال دیکھتے ہیں۔ آئیے Listطلباء کو مبارکباد کی لائنوں پر مشتمل ایک بنائیں:
List<String> list = new ArrayList<>();
list.add("Hello");
list.add("Обучающимся");
list.add("На");
list.add("JavaRush");
اب ہمیں اس کے لیے ایک تکرار کرنے والا ملے گا اور کنسول میں موجود تمام لائنوں کو پرنٹ کریں گے:
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
    System.out.println(iterator.next());
}
اب وہاں ایک "بٹلینیک" ہو گا: جاوا کلیکشنز، جیسا کہ آپ شاید جانتے ہوں گے (اور اگر آپ نہیں جانتے ہیں، تو اس کا پتہ لگائیں)، انٹرفیس کو بڑھا دیں Iterable، لیکن اس کا مطلب یہ نہیں ہے کہ صرف List، Setاور Queueایک تکرار کرنے والے کو سپورٹ کریں۔ کے لیے java Map iteratorبھی تعاون یافتہ ہے، لیکن اس کے لیے طلب کیا جانا چاہیے Map.entrySet():
Map<String, Integer> map = new HashMap<>();
Iterator mapIterator = map.entrySet().iterator();
پھر طریقہ ایک "کلید" - "قدر" جوڑی پر مشتمل next() ایک آبجیکٹ واپس کرے گا ۔ Entryپھر سب کچھ اسی کے ساتھ ہے List:
while (mapIterator.hasNext()) {
    Map.Entry<String, Integer> entry = mapIterator.next();
    System.out.println("Key: " + entry.getKey());
    System.out.println("Value: " + entry.getValue());
}
آپ سوچتے ہیں: "رک جاؤ. ہم انٹرفیس کے بارے میں بات کر رہے ہیں، اور مضمون کا عنوان ہے "پیٹرن"۔ یہ ہے، iterator پیٹرن Iterator انٹرفیس ہے؟ یا انٹرفیس ایک پیٹرن ہے؟ اگر یہ لفظ پہلی بار ظاہر ہوتا ہے تو، میں آپ کو ایک حوالہ دیتا ہوں: ایک پیٹرن ایک ڈیزائن پیٹرن ہے، ایک مخصوص طرز عمل جس کی ایک کلاس یا بہت سی باہم منسلک کلاسوں کو عمل کرنا چاہیے۔ جاوا میں ایک تکرار کرنے والا کسی بھی شے کے لئے لاگو کیا جاسکتا ہے جس کی اندرونی ساخت میں تکرار شامل ہے، اور آپ ان طریقوں کے دستخط کو تبدیل کرسکتے ہیں جن پر بات کی جارہی ہے۔ پیٹرن کو لاگو کرتے وقت سب سے اہم چیز وہ منطق ہے جس پر کلاس کو عمل پیرا ہونا چاہیے۔ تکرار کرنے والا انٹرفیسList, Set, Queue, Map اسی نام کے پیٹرن کا ایک نجی نفاذ ہے، جو پروگرامر کی صوابدید پر تیار شدہ ڈھانچے ( ) اور دوسروں پر لاگو ہوتا ہے ۔ Iterator انٹرفیس کو بڑھا کر، آپ ایک پیٹرن کو نافذ کرتے ہیں، لیکن پیٹرن کو نافذ کرنے کے لیے آپ کو انٹرفیس کو بڑھانے کی ضرورت نہیں ہے۔ ایک سادہ سی تشبیہ: تمام مچھلیاں تیرتی ہیں، لیکن ہر وہ چیز جو تیرتی ہے مچھلی نہیں ہوتی۔ ایک مثال کے طور پر، میں نے لفظ لینے کا فیصلہ کیا۔ مزید خاص طور پر، ایک اسم۔ یہ حصوں پر مشتمل ہے: سابقہ، جڑ، لاحقہ اور اختتام۔ کسی لفظ کے کچھ حصوں کے لیے، ہم ایک انٹرفیس اور کلاسز بنائیں گے WordPartجو اسے بڑھاتے ہیں: Prefix, Root, Suffix и Ending:
interface WordPart {
    String getWordPart();
}

static class Root implements WordPart {

    private String part;

    public Root(String part) {
        this.part = part;
    }

    @Override
    public String getWordPart() {
        return part;
    }
}

static class Prefix implements WordPart {

    private String part;

    public Prefix(String part) {
        this.part = part;
    }

    @Override
    public String getWordPart() {
        return part;
    }
}

static class Suffix implements WordPart {

    private String part;

    public Suffix(String part) {
        this.part = part;
    }

    @Override
    public String getWordPart() {
        return part;
    }
}

static class Ending implements WordPart {

    private String part;

    public Ending(String part) {
        this.part = part;
    }

    @Override
    public String getWordPart() {
        return part;
    }
}
پھر کلاس Word(لفظ) میں حصے ہوں گے، اور ان کے علاوہ ہم لفظ میں حصوں کی تعداد کی عکاسی کرنے والا ایک عدد بھی شامل کریں گے:
public class Word {

    private Root root;
    private Prefix prefix;
    private Suffix suffix;
    private Ending ending;
    private int partCount;

    public Word(Root root, Prefix prefix, Suffix suffix, Ending ending) {
        this.root = root;
        this.prefix = prefix;
        this.suffix = suffix;
        this.ending = ending;
        this.partCount = 4;
    }

    public Word(Root root, Prefix prefix, Suffix suffix) {
        this.root = root;
        this.prefix = prefix;
        this.suffix = suffix;
        this.partCount = 3;

    }

    public Word(Root root, Prefix prefix) {
        this.root = root;
        this.prefix = prefix;
        this.partCount = 2;
    }

    public Word(Root root) {
        this.root = root;
        this.partCount = 1;
    }

    public Root getRoot() {
        return root;
    }

    public Prefix getPrefix() {
        return prefix;
    }

    public Suffix getSuffix() {
        return suffix;
    }

    public Ending getEnding() {
        return ending;
    }

    public int getPartCount() {
        return partCount;
    }

    public boolean hasRoot() {
        return this.root != null;
    }

    public boolean hasPrefix() {
        return this.prefix != null;
    }

    public boolean hasSuffix() {
        return this.suffix != null;
    }

    public boolean hasEnding() {
        return this.ending != null;
    }
ٹھیک ہے، ہمارے پاس چار اوورلوڈ کنسٹرکٹرز ہیں (سادگی کے لیے، فرض کریں کہ ہمارے پاس صرف ایک لاحقہ ہو سکتا ہے)۔ ایک اسم ایک سابقہ ​​پر مشتمل نہیں ہو سکتا، لہذا ایک پیرامیٹر والے کنسٹرکٹر کے لیے ہم روٹ سیٹ کریں گے۔ اب آئیے ایٹریٹر پیٹرن کا نفاذ لکھتے ہیں: WordIterator، 2 طریقوں کو اوور رائیڈ کرتے ہوئے: hasNext()اور next():
public class WordIterator implements Iterator<Word.WordPart> {

    private Word word;
    private int wordPartsCount;

    public WordIterator(Word word) {
        this.word = word;
        this.wordPartsCount = word.getPartCount();
    }

    @Override
    public boolean hasNext() {
        if (wordPartsCount == 4) {
            return word.hasPrefix() || word.hasRoot() || word.hasSuffix() || word.hasEnding();
        } else if (wordPartsCount == 3) {
            return word.hasPrefix() || word.hasRoot() || word.hasSuffix();
        } else if (wordPartsCount == 2) {
            return word.hasPrefix() || word.hasRoot();
        } else if (wordPartsCount == 1) {
            return word.hasRoot();
        }
        return false;
    }

    @Override
    public Word.WordPart next() throws NoSuchElementException {
        if (wordPartsCount <= 0) {
            throw new NoSuchElementException("No more elements in this word!");
        }

        try {
            if (wordPartsCount == 4) {
                return word.getEnding();
            }
            if (wordPartsCount == 3) {
                return word.getSuffix();
            }
            if (wordPartsCount == 2) {
                return word.getPrefix();
            }
            return word.getRoot();
        } finally {
            wordPartsCount--;
        }
    }
}
جو کچھ باقی ہے وہ کلاس کو تکرار کرنے والے کو تفویض کرنا ہے Word:
public class Word implements Iterable<Word.WordPart> {@Override
	public Iterator<WordPart>iterator() {
    		return new WordIterator(this);
	}}
اب آئیے لفظ "رش" کا ایک شکلی تجزیہ کرتے ہیں:
public class Main {
    public static void main(String[] args) {
        Word.Root root = new Word.Root("беж");
        Word.Prefix prefix = new Word.Prefix("пере");
        Word.Suffix suffix = new Word.Suffix("к");
        Word.Ending ending = new Word.Ending("a");

        Word word = new Word(root, prefix, suffix, ending);

        Iterator wordIterator = word.iterator();
        while (wordIterator.hasNext()) {
            Word.WordPart part = (Word.WordPart) wordIterator.next();
            System.out.println(part.getClass() + ": " + part.getWordPart());
        }
    }
}
براہ کرم نوٹ کریں کہ میرے ایٹریٹر پیٹرن کے نفاذ میں، میں نے درج ذیل آؤٹ پٹ آرڈر کا انتخاب کیا:
  1. ختم
  2. لاحقہ
  3. تسلی
  4. جڑ
جب آپ اپنا ایٹریٹر ڈیزائن کرتے ہیں، تو آپ اپنی مرضی کے مطابق تکرار الگورتھم کی وضاحت کر سکتے ہیں۔ آپ کی پڑھائی میں اچھی قسمت!
تبصرے
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION