JavaRush /Java блогы /Random-KK /Бақылаушы үлгісі

Бақылаушы үлгісі

Топта жарияланған
The Gang of Four жазғандай (4 жоғары деңгейлі әзірлеушілердің «Нысанға бағытталған дизайн үлгілері» кітабына сілтеме жасай отырып), бұл үлгінің мақсаты an objectілер арасындағы «бірден көпке» тәуелділікті анықтау болып табылады. бір нысанның күйі өзгерсе, оған тәуелділердің барлығы бұл туралы хабардар етіледі және автоматты түрде жаңартылады. Бұл үлгі сондай-ақ деп аталады: Тәуелділер (бағыныңқылар) немесе Жариялау-жазылу (баспагер - жазылушы). Бірақ оны католиктік шіркеудің мысалы арқылы анықтауға тырысайық :) Бұл шіркеудің ілімдеріне сенетін ізбасарлары бар. Кез келген жаңа догмалар (міндетті сенімдер) және тағы басқалар пайда болған кезде, бұл адамдар олар туралы білуі керек. Бірақ бұл үлгіні пайдаланып бағдарламалау тілінде мұны қалай сипаттауға болады? 1. Бізде «шіркеудің дауысы» (шіркеудің өзі немесе экс соборды таратқанда Папа), яғни шіркеуде жаңалықтарды жариялайтын белгілі бір хабар таратушы немесе субъект. 2. Бұл шіркеудің приходтары, яғни маңызды оқиғалардан хабардар болғысы келетін кейбір бақылаушылар бар. Тиісінше, бүгінде 1,3 миллиард приход болуы мүмкін, ал ертең азды-көпті болуы мүмкін. Сіз тек осы шіркеуде жүргендерге хабарлауыңыз керек (қайтадан атеисттерді мазалаудың қажеті жоқ :). Осылайша, мұның барлығын келесідей көрсетуге болады: өз отарына бір нәрсе туралы айтатын шіркеу бар, онда сіз тіркеле аласыз немесе керісінше оны қалдыра аласыз:
public interface Church {
    void registerParishioner(Parishioner parishioner);
    void removeParishioner(Parishioner parishioner);
    void notifyParishioners();
}
Осы әдістерді жүзеге асыратын нақты католик шіркеуі бар, сонымен қатар жаңалықтар мен осы жаңалықтарды тарату керек адамдардың тізімі:
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);
    }
}
Шіркеуге кіруге немесе шығуға болатын приход бар (codeты жеңілдету үшін біз оған кіруге ғана рұқсат етеміз :)
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);
    }
}
Тиісінше, ол келесідей жұмыс істейді:
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 года");
    }
}
және бағдарламаның нәтижесі:
Мартин Лютер узнал новость: Инквизиция была ошибкой... месса Mea Culpa 12 марта 2000 года
Жан Кальвин узнал новость: Инквизиция была ошибкой... месса Mea Culpa 12 марта 2000 года
Анау. Шіркеуде жаңалық пайда болғаннан кейін, осы шіркеудің тіркелген мүшелерінің қатарында болғандардың барлығына бұл туралы хабарланады. Бұл іске асырудың қандай кемшіліктері бар: 1. Біріншіден, тіркелуге және жаңалықтар алуға болатын интерфейс тек осы шіркеуге ғана қатысты емес (бұл қажет болуы мүмкін). Сондықтан оны бірден бөлек бақыланатын интерфейске жылжытуға болады. 2. Дәл солай шіркеу шіркеушілерімен де жасалуы мүмкін, атап айтқанда, жаңарту әдісін бөлек интерфейске жылжытыңыз және оны қалаған приходқа енгізіңіз. Сонда бұл әдісті жалпы алғанда католик шіркеуінің приходтары емес, мысалы, эльфтер өмір сүретіндер («Жалғыз мүйіздіге жол» қозғалысын білдіреді) қолдана алады. Анау. жаңарту әдісімен Observer интерфейсін жасаңыз. Соңында не болады:
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);
    }
}
Осылайша: Біз шіркеу мен приходтардың арасындағы «байланысты әлсіретіп тастадық», бұл табиғи түрде тек бағдарламалауда жақсы :) Тақырыпта (католик шіркеуінде) тек тыңдаушылардың (приходтардың) тізімі бар және жаңалықтарды (өзгерістерді) алған кезде бұл жаңалықты таратады. тыңдаушыларына. Сіз енді кез келген басқа ұйымды (мысалы, протестанттық шіркеу) жасай аласыз және жаңалықтарды «сіздің» тыңдаушыларыңызға тарата аласыз. Сондай-ақ, 2-сынып деректері (дәлірек, Бақыланатын сынып және Бақылаушы интерфейсі) java.util java бумасында қолжетімді болғанын, бірақ қазір олар java 9 (https://docs.oracle. com/en/java/javase/15/ docs/api/java.base/java/util/Observable.html): Ескірген. Бұл сынып пен Observer интерфейсі ескірген. Observer және Observable қолдайтын оқиға үлгісі айтарлықтай шектеулі, Observable арқылы жеткізілетін хабарландырулардың реті анықталмаған және күй өзгерістері хабарландырулармен бір-бірден сәйкес келмейді. Оқиға үлгісі үшін java.beans бумасын пайдалануды қарастырыңыз. Ағындар арасында сенімді және реттелген хабар алмасу үшін java.util.concurrent бумасындағы қатарлас деректер құрылымдарының бірін пайдалануды қарастырыңыз. Реактивті ағындар стилін бағдарламалау үшін Flow API қараңыз. Сондықтан оларды пайдаланудың қажеті жоқ. Оның орнына басқаларды қолдануға болады, бірақ үлгінің мәні өзгермейді. Мысалы, java.beans бумасынан PropertyChangeListener (жазылған қажетсіз сыныптарды жазбау үшін) қолданып көрейік. Оның қалай болатынын көрейік: пәндік сынып:
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;
    }
}
және тыңдаушылар сыныбы:
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);
    }
}
Келесі codeты орындасақ:
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 год");
}
Біз келесі нәтижені аламыз:
Мартин Лютер жаңалықты білді: Мария Мәриям мінсіз туылған... бұқа Инеффабorс Деус... 1854 жылы 8 желтоқсанда Рим Папасы Пиус IX Джон Кальвин жаңалықты білді: Мария Мәриям мінсіз туылған... Бұқа Ineffabilis Deus ... 1854 жылдың 8 желтоқсаны Рим Папасы Пиус IX Мартин Лютер жаңалықты білді: Рим Папасы қателеспейді... әрине, әрқашан емес, бірақ ол шіркеуден бұрынғы собордың ілімдерін таратқанда ғана... Бірінші Ватикан кеңесі 1869 ж. Джон Кальвин білді. жаңалық: Рим Папасы қателеспейді... әрине, әрқашан емес, бірақ ол шіркеудің экс-кафедрасының ілімін таратқанда ғана... Бірінші Ватикан кеңесі 1869 ж.
Пікірлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION