什么是觀察者模式(Observer Pattern)
觀察者模式定義了對(duì)象之間的一對(duì)多依賴。這樣一來,當(dāng)一個(gè)對(duì)象狀態(tài)改變時(shí)它的所有依賴者都會(huì)收到通知并自動(dòng)更新。
觀察者模式的應(yīng)用
觀察者模式的應(yīng)用很廣泛。例如在Android開發(fā)時(shí)需要對(duì)控件注冊(cè)事件監(jiān)聽,控件屬于被觀察者,在該控件上所注冊(cè)的事件屬于觀察者,當(dāng)控件發(fā)生變化時(shí)相應(yīng)的監(jiān)聽事件會(huì)立即做出回應(yīng)。我想大家都有自己喜歡的微信公眾號(hào),其實(shí)微信公眾號(hào)的訂閱、推送很好的體現(xiàn)了觀察者模式。當(dāng)我們想及時(shí)獲得自己喜歡的公號(hào)的更新就得先關(guān)注它,然后公號(hào)有更新時(shí)會(huì)第一時(shí)間通知它的每一位仰慕者。
設(shè)計(jì)模式來源于生活,細(xì)細(xì)品味生活能夠更好的去理解設(shè)計(jì)模式。
觀察者模式所涉及的 OO 設(shè)計(jì)原則
實(shí)現(xiàn)交互對(duì)象之間的松耦合。
何為對(duì)象之間的松耦合?松耦合就是兩個(gè)對(duì)象可以交互,但是不太清楚彼此的細(xì)節(jié)。更通俗一點(diǎn)來說就是你和你的手機(jī)就是松耦合的,你可以很輕松的玩耍你的手機(jī)(你和手機(jī)進(jìn)行者交互),但你并知道手機(jī)內(nèi)部的實(shí)現(xiàn),手機(jī)也更不知道使用者是誰啦。
封裝變化。
多用組合,少用繼承。
針對(duì)接口編程,不針對(duì)實(shí)現(xiàn)編程。
觀察者模式 Java 代碼實(shí)現(xiàn)及分析
分析
此 Demo 借用模擬微信公眾號(hào)簡(jiǎn)單地實(shí)現(xiàn)了觀察者模式。
WeChatPublicNumber 是所有微信公眾號(hào)的公共接口,所有具體的微信公眾號(hào)都要實(shí)現(xiàn)此接口,CnboJavaDev 就是一個(gè)實(shí)現(xiàn)此接口的微信公眾號(hào)(我決定了,我以后的微信公眾號(hào)就叫此名了,嘻嘻)。WeChatPublicNumber 提供了用戶訂閱 registerUser(User user) 和取消訂閱的方法 removeUser(User user),還有推送更新的方法 notifyUsers()。
User 是所有用戶的公共接口,此接口提供了更新方法 update() 和文章閱讀方法 readArticle() (此方法主要用來測(cè)試打印)。Facebook 和 Google 實(shí)現(xiàn)了 User 接口。
TestObserver 用于對(duì)此 Demo 的測(cè)試。
Demo 的 UML 類圖

- WeChatPublicNumber.java
/**
* WeChatPublicNumber(微信公眾號(hào)接口)
* @author cnbo
*/
public interface WeChatPublicNumber {
//用戶訂閱公號(hào)
public void registerUser(User user);
//用戶取消訂閱
public void removeUser(User user);
//向所有訂閱用戶推送更新
public void notifyUsers();
}
- Article.java
/**
* 文章(別亂想哦)
* @author cnbo
*
*/
public class Article {
/** 文章的標(biāo)題 */
private String title;
/** 文章的作者 */
private String author;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
@Override
public String toString() {
return "title:" + title + "; author:" + author;
}
}
- User.java
/**
* 微信用戶接口
* @author cnbo
*
*/
public interface User {
public void update(Article article);
public void readAritcle();
}
- CnboJavaDev.java
/**
* CnboJavaDev是一個(gè)實(shí)現(xiàn)了接口WeChatPublicNumber
* 的具體的公號(hào)
* @author cnbo
*/
public class CnboJavaDev implements WeChatPublicNumber {
private Article article;
private List<User> users;
public CnboJavaDev() {
users = new ArrayList<>();
}
@Override
public void registerUser(User user) {
if (users != null) {
users.add(user);
}
}
@Override
public void removeUser(User user) {
if (users != null && users.contains(user)) {
users.remove(user);
}
}
//發(fā)布文章
public void publishArticle() {
notifyUsers();
}
//向所有訂閱者推送文章
@Override
public void notifyUsers() {
if (users == null) {
return;
}
for (User user : users) {
user.update(article);
user.readAritcle();
}
}
public void addArticle(Article article) {
this.article = article;
publishArticle();
}
}
- Facebook.java
/**
* 微信用戶Facebook
* @author cnbo
*
*/
public class Facebook implements User {
private Article article;
private WeChatPublicNumber weChatPublicNumber;
public Facebook(WeChatPublicNumber weChatPublicNumber) {
this.weChatPublicNumber = weChatPublicNumber;
weChatPublicNumber.registerUser(this);
}
@Override
public void update(Article article) {
this.article = article;
}
@Override
public void readAritcle() {
System.out.println("facebook read " + article);
}
}
- Google.java
/**
* 微信用戶Google
* @author cnbo
*/
public class Google implements User {
private Article article;
private WeChatPublicNumber weChatPublicNumber;
public Google(WeChatPublicNumber weChatPublicNumber) {
this.weChatPublicNumber = weChatPublicNumber;
weChatPublicNumber.registerUser(this);
}
@Override
public void update(Article article) {
this.article = article;
}
@Override
public void readAritcle() {
System.out.println("google read " + article);
}
}
- TestObserver.java
/*
* 測(cè)試觀察者模式
* @author cnbo
*/
public class TestObserver {
public static void main(String[] args) {
CnboJavaDev cnboJavaDev = new CnboJavaDev();
//facebook和google關(guān)注了cnboJavaDev(如果我真被facebook和google
//關(guān)注了,那我會(huì)興奮成神經(jīng)的,哈哈)
User facebook = new Facebook(cnboJavaDev);
User google = new Google(cnboJavaDev);
Article article1 = getArticle("學(xué)習(xí)筆記之單例設(shè)計(jì)模式", "cnbo");
//cnboJavaDev發(fā)布一篇新文章article1,同時(shí)facebook和google
//都接收到了更新,然后他哥倆有滋有味的讀者cnbo的文章。
cnboJavaDev.addArticle(article1);
Article article2 = getArticle("學(xué)習(xí)筆記之策略設(shè)計(jì)模式", "cnbo");
cnboJavaDev.addArticle(article2);
}
public static Article getArticle(String title, String author) {
Article article = new Article();
article.setTitle(title);
article.setAuthor(author);
return article;
}
}