JavaRush /Java Blog /Random-TW /觀察者模板

觀察者模板

在 Random-TW 群組發布
正如四人幫所寫(參考 4 位頂尖開發人員所寫的《物件導向設計模式》一書),該模式的目的是定義物件之間的一對多依賴關係,當一個物件的狀態發生變化,所有依賴它的物件都會收到通知並自動更新。 這種模式也稱為:Dependents(下屬)或Publish-Subscribe(發布者-訂閱者)。但讓我們試著用天主教會的例子來弄清楚:)它有相信這個教會教義的追隨者。當任何新的教條(強制性信條)和更多出現時,這些人應該知道它們。 但是如何使用這種模式用程式語言來描述呢? 1.我們有「教會之聲」(教會本身或教宗在廣播ex cathedra時),即某位廣播員或主體在教會中宣告新聞。2. 這個教堂有教區居民,即一些想要了解重要事件的觀察員。因此,今天可能有13億教區居民,明天可能會更多或更少。而且你只需要通知那些在這個教會的人(不需要再打擾無神論者:)。因此,這一切都可以表達如下:有一個教會會告訴它的羊群一些事情,你可以在其中登記,或者相反,留下它:
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);
    }
}
有一個教區居民可以進入或離開教堂(為了簡化代碼,我們只允許他進入:)
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. 首先,你可以註冊和接收訊息的介面可能不只涉及這個教會(這可能是必要的)。因此,可以立即將其移至單獨的 Observable 介面中。2. 對於教會教區居民也可以這樣做,即將更新方法移至單獨的介面中並為所需的教區居民實現它。那麼這種方法將不會被天主教會的教友普遍使用,而是被那些生活在精靈存在的人(即「獨角獸之路」運動)所使用。那些。使用更新方法建立一個觀察者介面。最終會發生什麼:
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 類資料(更準確地說,Observable 類別和Observer 介面)在java.util java 套件中可用,但現在它們在java 9 中已棄用(https://docs.oracle.java) 。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);
    }
}
如果我們執行以下程式碼:
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 год");
}
我們得到以下結果:
馬丁路德得知消息:聖母瑪利亞是聖母無染原罪...公牛Ineffabilis Deus... 1854 年12 月8 日教宗庇護九世約翰加爾文獲悉消息:聖母瑪利亞是聖母無染原罪...公牛Ineffabilis Deus ... 1854 年12 月8 日,教宗庇護九世馬丁路德得知這一消息:教宗是絕對正確的...當然並不總是如此,但只有當當他在大教堂前傳播教會的教義時...第一次梵蒂岡大公會議1869 年約翰·加爾文得知新聞:教皇是絕對正確的……當然並不總是如此,但只有當他廣播前大教堂的教義時…1869 年第一屆梵蒂岡大公會議
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION