JavaRush /Java blogi /Random-UZ /Kuzatuvchi shablon

Kuzatuvchi shablon

Guruhda nashr etilgan
To'rtlik to'dasi yozganidek (to'rtta yuqori darajadagi ishlab chiquvchilarning "Ob'ektga yo'naltirilgan dizayn naqshlari" kitobiga ishora qilib), ushbu naqshning maqsadi ob'ektlar o'rtasidagi birdan ko'pga bog'liqlikni aniqlashdan iborat. bitta ob'ektning holati o'zgaradi, unga bog'liq bo'lganlarning barchasi bu haqda xabardor qilinadi va avtomatik ravishda yangilanadi. Bu naqsh shuningdek deyiladi: qaramlar (bo'ysunuvchilar) yoki nashr etish-obuna bo'lish (noshir - obunachi). Ammo keling, buni katolik cherkovining misolidan foydalanib aniqlashga harakat qilaylik :) Bu cherkovning ta'limotiga ishonadigan izdoshlari bor. Har qanday yangi dogmalar (majburiy e'tiqodlar) va boshqalar paydo bo'lganda, bu odamlar ular haqida bilishlari kerak. Ammo bu naqshni dasturlash tilida qanday tasvirlash mumkin? 1. Bizda "cherkovning ovozi" (cherkovning o'zi yoki sobiq katedrani eshittirishda Papa), ya'ni cherkovda yangiliklarni e'lon qiladigan ma'lum bir teleradiokompaniya yoki mavzu. 2. Bu cherkovning parishionlari, ya'ni muhim voqealardan xabardor bo'lishni xohlaydigan ba'zi kuzatuvchilar bor. Shunga ko'ra, bugungi kunda 1,3 milliard parishioner bo'lishi mumkin, ertaga esa ko'p yoki kamroq bo'lishi mumkin. Va siz faqat bu cherkovda bo'lganlarni xabardor qilishingiz kerak (yana ateistlarni bezovta qilishning hojati yo'q :). Shunday qilib, bularning barchasini quyidagicha ifodalash mumkin: o'z suruviga biror narsa haqida gapiradigan cherkov bor, unda siz ro'yxatdan o'tishingiz yoki aksincha, uni tark etishingiz mumkin:
public interface Church {
    void registerParishioner(Parishioner parishioner);
    void removeParishioner(Parishioner parishioner);
    void notifyParishioners();
}
Ushbu usullarni qo'llash bilan o'ziga xos katolik cherkovi, shuningdek, yangiliklar va ushbu yangilik efirga uzatilishi kerak bo'lgan odamlar ro'yxati mavjud:
public class CatholicChurch implements Church {
    private List<parishioner> parishioners;
    private String newsChurch;

    public CatholicChurch() {
        parishioners = new ArrayList<>();
    }

    public void setNewsChurch(String news) {
        this.newsChurch = news;
        notifyParishioners();
    }

    @Override
    public void registerParishioner(Parishioner parishioner) {
        parishioners.add(parishioner);
    }

    @Override
    public void removeParishioner(Parishioner parishioner) {
        parishioners.remove(parishioner);
    }

    @Override
    public void notifyParishioners() {
        for (Parishioner parishioner : parishioners)
            parishioner.update(newsChurch);
    }
}
Cherkovga kirishi yoki chiqishi mumkin bo'lgan parishioner bor (kodni soddalashtirish uchun biz unga kirishiga ruxsat beramiz :)
public class Parishioner {

    private String name;

    public Parishioner(String name, Church church) {
        this.name = name;
        church.registerParishioner(this);
    }

    void update(String newsChurch) {
        System.out.println(name + "узнал новость: " + newsChurch);
    }
}
Shunga ko'ra, u quyidagicha ishlaydi:
public class Main {
    public static void main(String[] args) {
        var catholicChurch = new CatholicChurch();

        new Parishioner("Мартин Лютер", catholicChurch);
        new Parishioner("Жан Кальвин", catholicChurch);

        catholicChurch.setNewsChurch("Инквизиция была ошибкой... месса Mea Culpa 12 марта 2000 года");
    }
}
va dastur natijasi:
Мартин Лютер узнал новость: Инквизиция была ошибкой... месса Mea Culpa 12 марта 2000 года
Жан Кальвин узнал новость: Инквизиция была ошибкой... месса Mea Culpa 12 марта 2000 года
Bular. Jamoatda yangilik paydo bo'lishi bilanoq, bu cherkovning ro'yxatdan o'tgan a'zolari qatorida bo'lgan har bir kishi bu haqda xabardor qilinadi. Ushbu amalga oshirishning kamchiliklari nimada: 1. Birinchidan, siz ro'yxatdan o'tishingiz va yangiliklarni olishingiz mumkin bo'lgan interfeys nafaqat ushbu cherkovga tegishli bo'lishi mumkin (bu talab qilinishi mumkin). Shuning uchun, buni darhol kuzatilishi mumkin bo'lgan alohida interfeysga o'tkazish mumkin edi. 2. Xuddi shu narsani cherkov parishionerlari bilan qilish mumkin, ya'ni yangilash usulini alohida interfeysga o'tkazing va uni kerakli parishioner uchun amalga oshiring. Keyin bu usulni umuman katolik cherkovining parishionlari emas, balki, masalan, elflar mavjudligida yashovchilar ("Yagona shoxga yo'l" harakati) qo'llashlari mumkin bo'ladi. Bular. yangilash usuli bilan Observer interfeysini yarating. Oxirida nima bo'ladi:
interface Observable {
    void registerObserver(Observer o);
    void removeObserver(Observer o);
    void notifyObservers();
}
public class CatholicChurch implements Observable {
    private List<observer> parishioners;
    private String newsChurch;

    public CatholicChurch() {
        parishioners = new ArrayList<>();
    }

    public void setNewsChurch(String news) {
        this.newsChurch = news;
        notifyObservers();
    }

    @Override
    public void registerObserver(Observer o) {
        parishioners.add(o);
    }

    @Override
    public void removeObserver(Observer o) {
        parishioners.remove(o);
    }

    @Override
    public void notifyObservers() {
        for (Observer o : parishioners)
            o.update(newsChurch);
    }
}
interface Observer {
    void update (String news);
}
public class Parishioner implements Observer {
    private String name;

    public Parishioner(String name, Observable o) {
        this.name = name;
        o.registerObserver(this);
    }

    @Override
    public void update(String news) {
        System.out.println(name + " узнал новость: " + news);
    }
}
Shunday qilib: Biz cherkov va parishionerlar o'rtasidagi "aloqani zaiflashtirdik", bu tabiiy ravishda faqat dasturlashda yaxshi :) Mavzu (katolik cherkovi) faqat tinglovchilar (parishionerlar) ro'yxatiga ega va yangiliklarni (o'zgarishlarni) qabul qilganda, bu yangilikni efirga uzatadi. tinglovchilariga. Endi siz boshqa har qanday tashkilot (masalan, protestant cherkovi) yaratishingiz va yangiliklarni "sizning" tinglovchilaringizga tarqatishingiz mumkin. Shuni ham hisobga olish kerakki, 2-sinf ma'lumotlari (aniqrog'i, Observable sinfi va Observer interfeysi) java.util java paketida mavjud edi, ammo endi ular java 9 (https://docs.oracle. com/en/java/javase/15/ docs/api/java.base/java/util/Observable.html): Eskirgan. Bu sinf va Observer interfeysi eskirgan. Observer va Observable tomonidan qo'llab-quvvatlanadigan hodisa modeli juda cheklangan, Observable tomonidan yuboriladigan bildirishnomalar tartibi aniqlanmagan va holat o'zgarishlari bildirishnomalar bilan birma-bir yozishmalarda emas. Voqealarning yanada boy modeli uchun java.beans to'plamidan foydalanishni o'ylab ko'ring. Mavzular o'rtasida ishonchli va tartibli xabar almashish uchun java.util.concurrent paketidagi bir vaqtda ma'lumotlar tuzilmalaridan birini ishlatishni o'ylab ko'ring. Reaktiv oqimlar uslubini dasturlash uchun Flow API ga qarang. Shuning uchun ulardan foydalanishning hojati yo'q. Va buning o'rniga siz boshqalardan foydalanishingiz mumkin, ammo naqshning mohiyati o'zgarmaydi. Masalan, java.beans paketidan PropertyChangeListener (allaqachon yozilgan keraksiz sinflarni yozmaslik uchun) dan foydalanishga harakat qilaylik. Keling, qanday bo'lishini ko'rib chiqaylik: mavzu klassi:
public class CatholicChurch {
    private String news;
    // используя support мы можем добавлять or удалять наших прихожан (слушателей)
    private PropertyChangeSupport support;

    public CatholicChurch() {
        support = new PropertyChangeSupport(this);
    }
    public void addPropertyChangeListener(PropertyChangeListener pcl) {
        support.addPropertyChangeListener(pcl);
    }

    public void removePropertyChangeListener(PropertyChangeListener pcl) {
        support.removePropertyChangeListener(pcl);
    }

    public void setNews(String value) {
        support.firePropertyChange("news", this.news, value);
        this.news = value;
    }
}
va tinglovchilar sinfi:
public class Parishioner implements PropertyChangeListener {
    private String name;

    public Parishioner(String name) {
        this.name = name;
    }

    public void propertyChange(PropertyChangeEvent evt) {
        this.setNews((String) evt.getNewValue());
    }

    public void setNews(String news) {
        System.out.println(name + " узнал новость: " + news);
    }
}
Agar biz quyidagi kodni bajarsak:
public static void main(String[] args) {
    CatholicChurch observable = new CatholicChurch();

    observable.addPropertyChangeListener(new Parishioner("Мартин Лютер"));
    observable.addPropertyChangeListener(new Parishioner("Жан Кальвин"));

    observable.setNews("Дева Мария имеет непорочное зачатие... булла Ineffabilis Deus... 8 декабря 1854 года Папа Пий IX");
    observable.setNews("Папа непогрешим... не всегда конечно, а только когда транслирует учение церкви ex cathedra... Первый Ватиканский собор 1869 год");
}
Biz quyidagi natijani olamiz:
Martin Lyuter yangilikni bilib oldi: Bokira Maryam beg'ubor tug'ilishdan ... buqa Ineffabilis Deus ... 1854 yil 8 dekabrda Papa Pius IX Jon Kalvin yangilikni bilib oldi: Bokira Maryam beg'ubor tug'ilishdan ... Buqa Ineffabilis Deus ... 1854-yil 8-dekabr Papa Pius IX Martin Lyuter yangilikni bilib oldi: Rim papasi aybsizdir... albatta, har doim ham emas, lekin u cherkovning sobiq sobori ta'limotlarini efirga uzatganda... Birinchi Vatikan kengashi 1869 yil Jon Kalvin bilib oldi. Yangiliklar: Papa aybsizdir... albatta, har doim ham emas, lekin u cherkov sobiq sobori haqidagi ta'limotlarni eshittirishda... Birinchi Vatikan kengashi 1869 yil
Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION