正如四人幫所寫(參考 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 年第一屆梵蒂岡大公會議
GO TO FULL VERSION