在我們?nèi)粘I钪?,有些人會有訂閱報紙的?jīng)歷,當我們訂閱時,都能定時的收到報紙,當我么取消訂閱時,就不會再收到報紙。
當然,互聯(lián)網(wǎng)普及之后,報紙逐漸減少。但是類似的也有許多,例如微信的公眾號,當我們訂閱了公眾號時,公眾號有新文章發(fā)布時就會推送到我們的微信上。
用戶3關(guān)注公眾號
公眾號把用戶3添加到關(guān)注用戶列表中,有新文章時推送給關(guān)注用戶列表中
用戶2取消關(guān)注,公眾號把用戶2從關(guān)注用戶列表中移除,有新文章時不再推送給用戶2
以上便是觀察這模式
介紹
觀察者模式定義對象間的一種一對多的依賴關(guān)系,當一個對象的狀態(tài)發(fā)生改變時,所有依賴于它的對象都得到通知并被自動更新。
觀察者模式又叫做發(fā)布-訂閱(Publish/Subscribe)模式、模型-視圖(Model/View)模式、源-監(jiān)聽器(Source/Listener)模式或從屬者(Dependents)模式。
發(fā)生改變的對象稱為觀察目標,而被通知的對象稱為觀察者,一個觀察目標可以對應多個觀察者,而且這些觀察者之間沒有相互聯(lián)系,可以根據(jù)需要增加和刪除觀察者,使得系統(tǒng)更易于擴展,這就是觀察者模式的模式動機。
結(jié)構(gòu)圖
時序圖
案例
案例就采用模擬公眾號訂閱的機制
注:以下代碼只是提供個思路
主題抽象類(公眾號)
public abstract class Subject {
List<UserObeserver> userList = new ArrayList<UserObeserver>();
public void addUser(UserObeserver userObeserver){
userList.add(userObeserver);
}
public void delUser(UserObeserver userObeserver){
userList.remove(userObeserver);
}
public void pushArticle(String articleContent){
for (UserObeserver userObeserver : userList) {
userObeserver.receiveArticle(this,articleContent);
}
}
public abstract String getSubjectName();
}
公眾號1
public class ConcreteSubject1 extends Subject{
@Override
public String getSubjectName() {
return "公眾號1";
}
}
公眾號2
public class ConcreteSubject2 extends Subject{
@Override
public String getSubjectName() {
return "公眾號2";
}
}
訂閱者接口(用戶)
public interface UserObeserver {
void receiveArticle(Subject subject, String articleContent);
}
用戶1
public class ConcreteUserObeserver1 implements UserObeserver {
@Override
public void receiveArticle(Subject subject,String articleContent) {
System.out.println("我是讀者1,公眾號名稱:"+subject.getSubjectName()+" 推出的新的文章內(nèi)容是"+articleContent);
}
}
用戶2
public class ConcreteUserObeserver2 implements UserObeserver {
@Override
public void receiveArticle(Subject subject,String articleContent) {
System.out.println("我是讀者2,公眾號名稱:"+subject.getSubjectName()+" 推出的新的文章內(nèi)容是"+articleContent);
}
}
測試類
public class Client {
public static void main(String[] args) {
ConcreteSubject1 subject1 = new ConcreteSubject1();
ConcreteSubject2 subject2 = new ConcreteSubject2();
ConcreteUserObeserver1 user1 = new ConcreteUserObeserver1();
ConcreteUserObeserver2 user2 = new ConcreteUserObeserver2();
//讀者1、2都訂閱公眾號1,讀者2訂閱了公眾號2
subject1.addUser(user1);
subject1.addUser(user2);
subject2.addUser(user2);
//公眾號發(fā)布消息
System.out.println("第一篇");
subject1.pushArticle("1.今天天氣不錯!");
subject2.pushArticle("1.今天天氣很不錯!");
//讀者1取消關(guān)注公眾號1,想去關(guān)注公眾號2,讀者2取消關(guān)注公眾號2
subject1.delUser(user1);
subject2.delUser(user2);
subject2.addUser(user1);
System.out.println("第二篇");
subject1.pushArticle("2.今天天氣一般般!");
subject2.pushArticle("2.今天天氣很一般般!");
}
}
測試結(jié)果
總結(jié)
這一模式中的關(guān)鍵對象是觀察目標和觀察者,一個目標可以有任意數(shù)目的與之相依賴的觀察者,一旦目標的狀態(tài)發(fā)生改變,所有的觀察者都將得到通知。
觀察者模式可以實現(xiàn)表示層和數(shù)據(jù)邏輯層的分離,并定義了穩(wěn)定的消息更新傳遞機制,抽象了更新接口,使得可以有各種各樣不同的表示層作為具體觀察者角色。
JDK中有內(nèi)置的觀察者模式,Observer接口和Observable類,有興趣的可以了解下。
延伸
觀察者模式中觀察者有沒有可能變成主題,也就是觀察者既可以保持自身的身份又可以發(fā)布新的消息?
當然可以,想現(xiàn)在的微博,你關(guān)注別人,你就能獲得那個人發(fā)布的消息,如果他也關(guān)注你,那么他也能收到你發(fā)布的消息。微信朋友圈亦是如此,當你們成為微信好友是,雙方都能收到彼此發(fā)的朋友圈。
用戶1
public class User1 extends Subject implements UserObeserver{
@Override
public void receiveArticle(Subject subject, String articleContent) {
System.out.println("我是用戶1,"+subject.getSubjectName()+" 推出的新的文章內(nèi)容是"+articleContent);
}
@Override
public String getSubjectName() {
return "用戶1";
}
}
用戶2
public class User2 extends Subject implements UserObeserver{
@Override
public void receiveArticle(Subject subject, String articleContent) {
System.out.println("我是用戶2,"+subject.getSubjectName()+" 推出的新的文章內(nèi)容是"+articleContent);
}
@Override
public String getSubjectName() {
return "用戶2";
}
}
測試類
public class Client {
public static void main(String[] args) {
User1 user1 = new User1();
User2 user2 = new User2();
//用戶1和用戶2互相加為好友
user1.addUser(user2);
user2.addUser(user1);
user1.pushArticle("1.今天天氣不錯!");
user2.pushArticle("1.今天天氣很不錯!");
//用戶2把用戶1給屏蔽了(注:應該從用戶1中去掉用戶2中的觀察者)
System.out.println("用戶2把用戶1給屏蔽了");
user1.delUser(user2);
user1.pushArticle("1.今天天氣不錯!");
user2.pushArticle("1.今天天氣很不錯!");
}
}
測試類中的用戶2把用戶1給屏蔽了,有些人可能思路轉(zhuǎn)不過來,為什么用戶2把用戶1給屏蔽了,用戶1要去刪除用戶2的對象?
換個思路就是用戶2不想在收到用戶1的消息,所以用戶1中維護的觀察者列表中要刪除這個對象。
代碼見Github地址