JavaRush /Blog Java /Random-MS /Templat pemerhati

Templat pemerhati

Diterbitkan dalam kumpulan
Seperti yang ditulis oleh Geng Empat (merujuk kepada buku "Corak Reka Bentuk Berorientasikan Objek" oleh 4 pembangun terkemuka), tujuan corak ini adalah untuk menentukan pergantungan satu-ke-banyak antara objek sedemikian rupa sehingga apabila keadaan satu objek berubah, semua yang bergantung padanya diberitahu tentang perkara ini dan dikemas kini secara automatik. Corak ini juga dipanggil: Tanggungan (orang bawahan) atau Publish-Subscribe (penerbit - pelanggan). Tetapi mari kita cuba memikirkannya menggunakan contoh Gereja Katolik :) Ia mempunyai pengikut yang percaya kepada ajaran gereja ini. Apabila sebarang dogma baharu (akidah wajib) dan banyak lagi muncul, orang-orang ini harus mengetahui tentang mereka. Tetapi bagaimana ini boleh diterangkan dalam bahasa pengaturcaraan menggunakan corak ini? 1. Kami mempunyai "suara gereja" (gereja itu sendiri atau Paus apabila menyiarkan ex cathedra), iaitu, penyiar atau subjek tertentu yang mengumumkan berita di gereja. 2. Terdapat ahli kariah gereja ini, iaitu beberapa pemerhati yang ingin mengambil tahu tentang peristiwa penting. Sehubungan itu, hari ini mungkin ada 1.3 bilion jemaah, dan esok mungkin ada lebih atau kurang. Dan anda hanya perlu memberitahu mereka yang berada di gereja ini (tidak perlu menyusahkan ateis lagi :). Oleh itu, semua ini boleh dinyatakan seperti berikut: Terdapat sebuah gereja yang akan memberitahu kawanannya tentang sesuatu, di mana anda boleh mendaftar atau, sebaliknya, meninggalkannya:
public interface Church {
    void registerParishioner(Parishioner parishioner);
    void removeParishioner(Parishioner parishioner);
    void notifyParishioners();
}
Terdapat Gereja Katolik khusus dengan pelaksanaan kaedah ini, serta berita dan senarai orang yang berita ini harus disiarkan:
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);
    }
}
Terdapat ahli kariah yang boleh masuk atau keluar dari gereja (untuk memudahkan kod, kami hanya membenarkan dia masuk :)
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);
    }
}
Oleh itu, ini adalah bagaimana ia akan berfungsi:
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 года");
    }
}
dan hasil program:
Мартин Лютер узнал новость: Инквизиция была ошибкой... месса Mea Culpa 12 марта 2000 года
Жан Кальвин узнал новость: Инквизиция была ошибкой... месса Mea Culpa 12 марта 2000 года
Itu. sebaik sahaja berita muncul di gereja, setiap orang yang berada dalam susunan ahli berdaftar gereja ini akan dimaklumkan mengenainya. Apakah kelemahan pelaksanaan ini: 1. Pertama, antara muka tempat anda boleh mendaftar dan menerima berita mungkin melibatkan bukan sahaja gereja ini (ini mungkin diperlukan). Oleh itu, adalah mungkin untuk mengalihkannya dengan segera ke antara muka Boleh Diperhatikan yang berasingan. 2. Perkara yang sama boleh dilakukan dengan umat gereja, iaitu, memindahkan kaedah kemas kini ke antara muka yang berasingan dan melaksanakannya untuk kariah yang dikehendaki. Kemudian kaedah ini akan dapat digunakan secara umum bukan oleh umat Gereja Katolik, tetapi, sebagai contoh, oleh mereka yang hidup dalam kewujudan bunian (bermaksud pergerakan "Jalan ke Unicorn"). Itu. buat antara muka Pemerhati dengan kaedah kemas kini. Apa yang akan berlaku pada akhirnya:
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);
    }
}
Oleh itu: Kami telah "melemahkan hubungan" antara gereja dan umat, yang secara semula jadi hanya baik dalam pengaturcaraan :) Subjek (gereja Katolik) hanya mempunyai senarai pendengar (para gereja) dan apabila menerima berita (perubahan), menyiarkan berita ini kepada pendengarnya. Anda kini boleh membuat sebarang entiti lain (contohnya, gereja Protestan) dan menyiarkan berita itu kepada pendengar "anda". Anda juga perlu mengambil kira bahawa data kelas 2 (lebih tepat lagi, kelas Observable dan antara muka Observer) tersedia dalam pakej java.util java, tetapi kini ia adalah Deprecation dengan java 9 (https://docs.oracle. com/en/java/javase/15/ docs/api/java.base/java/util/Observable.html): Tidak digunakan lagi. Kelas ini dan antara muka Pemerhati telah ditamatkan. Model acara yang disokong oleh Observer dan Observable agak terhad, susunan pemberitahuan yang dihantar oleh Observable tidak ditentukan, dan perubahan keadaan bukan dalam surat-menyurat satu-untuk-satu dengan pemberitahuan. Untuk model acara yang lebih kaya, pertimbangkan untuk menggunakan pakej java.beans. Untuk pemesejan yang boleh dipercayai dan teratur antara urutan, pertimbangkan untuk menggunakan salah satu struktur data serentak dalam pakej java.util.concurrent. Untuk pengaturcaraan gaya aliran reaktif, lihat API Aliran. Oleh itu tidak perlu menggunakannya. Dan anda boleh menggunakan yang lain sebaliknya, tetapi intipati corak tidak akan berubah. Sebagai contoh, mari cuba gunakan PropertyChangeListener (supaya tidak menulis kelas yang tidak perlu yang telah ditulis) daripada pakej java.beans. Mari lihat bagaimana keadaannya: kelas subjek:
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;
    }
}
dan kelas pendengar:
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);
    }
}
Jika kita melaksanakan kod berikut:
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 год");
}
Kami mendapat keputusan berikut:
Martin Luther mengetahui berita itu: Perawan Maria adalah dari Pengandungan Tanpa Noda... lembu Ineffabilis Deus... 8 Disember 1854 Paus Pius IX John Calvin mengetahui berita itu: Perawan Maria adalah dari Pengandungan Tanpa Noda... Bull Ineffabilis Deus ... 8 Disember 1854 Paus Pius IX Martin Luther mengetahui berita itu: Paus adalah maksum... tidak semestinya, tetapi hanya apabila dia menyiarkan ajaran gereja ex cathedra... Majlis Vatikan Pertama 1869 John Calvin belajar berita: Paus adalah maksum... tidak semestinya, tetapi hanya apabila dia menyiarkan ajaran gereja ex cathedra... Majlis Vatikan Pertama 1869
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION