觀察者模式,又被稱為發布—訂閱模式、源—收聽者模式,是軟件設計模式的一種。在此種模式中,一個目標物件管理所有相依與它的觀察者物件,並且在它本身的狀態改變時主動發出同時,此種模式通常被用來實現事件處理系統。
觀察者模式一般包含以下四種角色:
抽象主題角色Watched:把所有對觀察者對象的引用保存在一個集合中,每個抽象主題角色都可以有任意數量的觀察者。抽象主題提供一個接口,可以增加和刪除觀察這角色。
抽象觀察者角色Watcher:為所有具體的觀察者定義一個接口,在得到主題的通知更新自己。
具體主題角色ConcreteWatched:在具體主題內部狀態改變時,給所有登記過的觀察者發出通知。
具體觀察者角色ConcreteWatcher:該角色實現抽象觀察者角色所要求的更新接口,以便使自身的狀態與主題的狀態相協調。
觀察者模式有很多實現方式,從根本上說,該模式必須包含兩個角色,觀察者和被觀察對象。比較直觀的一種是使用“注冊”—“通知”—“撤銷通知”的形式。
觀察者將自己注冊到被觀察對象中,被觀察者將觀察者放在一個容器中。
被觀察者對象發生某種變化時,從容器中得到所有被注冊過的觀察者,將變化通知觀察者。
觀察者將自己注冊到被觀察者的容器時,被觀察者不應該過問觀察者的具體類型,而是應該使用觀察者的接口。這樣的好處是:假定程序還有別的觀察者,那麼只要這個觀察者也是相同的接口即可。一個被觀察者可以對應多個觀察者,當被觀察者發生變化的時候,他可以將消息一一通知給所有的觀察者。如下圖所示:

具體到一個應用場景就是:讀者訂閱新聞,每一個讀者都可以通過regist來訂閱新聞,通過remove來取消訂閱,當有新聞到來時,使用sendNews來通知每一位訂閱的讀者來收取新聞。
下面用代碼來實現上面的實例:
抽象主題角色Watched:新聞接口,定義訂閱、取消訂閱和推送新聞三個方法
public interface Watched
{
//訂閱新聞
void registeSubscriber(Watcher f_subscriber);
//取消訂閱
void removeSubscriber(Watcher f_subscriber);
//推送新聞
void sendNews();
}
抽象觀察者角色Watcher:讀者接口,定義了獲取新聞的方法
public interface Watcher
{
//獲取新聞
void updateNews();
}
具體主題角色ConcreteWatched,即被觀察者,實現了Watched接口:
import java.util.ArrayList;
import java.util.List;
/*
* 具體被觀察者
* 新聞發布者
*/
public class ConcreteWatched implements Watched
{
private List<Watcher> subList=new ArrayList<Watcher>();
@Override
public void registeSubscriber(Watcher f_subscriber)
{
subList.add(f_subscriber);
}
@Override
public void removeSubscriber(Watcher f_subscriber)
{
subList.remove(f_subscriber);
}
@Override
public void sendNews()
{
System.out.println("開始本輪新聞推送!");
for (Watcher watcher : subList)
{
watcher.updateNews();
}
System.out.println("本次新聞推送結束!");
}
}
具體觀察者角色ConcreteWatcher,即觀察者對象
/*
* 具體的觀察者
* 讀者
*/
public class ConcreteWatcher implements Watcher
{
private String username;
public ConcreteWatcher(String username)
{
super();
this.username = username;
}
@Override
public void updateNews()
{
System.out.println(username+"獲取到最新的新聞了!");
}
}
下面是一個測試用例:
import org.junit.Test;
public class WatchTest
{
@Test
public void test()
{
ConcreteWatched concreteWatched=new ConcreteWatched();
Watcher watcher1=new ConcreteWatcher("讀者A");
Watcher watcher2=new ConcreteWatcher("讀者B");
Watcher watcher3=new ConcreteWatcher("讀者C");
//訂閱新聞
concreteWatched.registeSubscriber(watcher1);
concreteWatched.registeSubscriber(watcher2);
concreteWatched.registeSubscriber(watcher3);
//推送新聞
concreteWatched.sendNews();
//讀者A取消訂閱
concreteWatched.removeSubscriber(watcher1);
//再次推送新聞
concreteWatched.sendNews();
}
}
執行結果:
