大話設計模式讀書筆記(十一) 觀察者模式

觀察者模式:

書中通過小菜描述同事在公司看股票行情,并請求前臺幫忙在老板回來時提醒同事,引出需求。將前臺通知同事老板回來的事寫成程序。

未用模式實現:

 1 //前臺類
 2 public class Secretary {
 3     private List<StockObserver> observers = new ArrayList<StockObserver>();
 4     private String action;
 5     //添加同事
 6     public void attach(StockObserver observer){
 7         observers.add(observer);
 8     }
 9     //待老板來時,前臺通過電話通知所有同事
10     public void notifyObserver(){
11         for (StockObserver o : observers) {
12             o.update();
13         }
14     }
15     public String getAction() {
16         return action;
17     }
18     public void setAction(String action) {
19         this.action = action;
20     }
21     
22 }

?

//同事類
 1 public class StockObserver {
 2     //姓名
 3     private String name;
 4     //前臺
 5     private Secretary secretary;
 6     public StockObserver(String name, Secretary secretary) {
 7         super();
 8         this.name = name;
 9         this.secretary = secretary;
10     }
11     public void update() {
12         System.out.println(secretary.getAction()+
13                 ","+name+"關閉股票行情,繼續工作!");
14     }
15 }

?

主方法
 1 public class Main {
 2     public static void main(String[] args) {
 3         //前臺小姐通知者
 4         Secretary tongzhizhe = new Secretary();
 5         //兩位公司同事
 6         StockObserver tongshi1 = new StockObserver("魏關姹", tongzhizhe);
 7         StockObserver tongshi2 = new StockObserver("易管查", tongzhizhe);
 8         //前臺幾下兩位同事
 9         tongzhizhe.attach(tongshi1);
10         tongzhizhe.attach(tongshi2);
11         //老板來了.前臺通知同事
12         tongzhizhe.setAction("老板來了");
13         tongzhizhe.notifyObserver();
14     }
15 }

?

? 代碼雖然將需求的基本功能實現了,但是同事類需要前臺小姐的狀態,前臺小姐需要增加同事。這是典型的雙向偶爾。這段代碼及違反了開放封閉原則,又違反了依賴倒轉原則。

解耦實現:

同事抽象類
//同事抽象類
public abstract class Observer {
private String name;
public abstract void update();
}
同事實現類
//同事類
public class StockObserver extends Observer{
//姓名
private String name;
private Subject subject;
public StockObserver(String name,Subject subject) {
super();
this.name = name;
this.subject = subject;
}
@Override
public void update() {
System.out.println(subject.getAction()+","+name+"關閉股票行情,繼續工作!");
}
}
//同事類
public class StockObserver2 extends Observer{
//姓名
private String name;
private Subject subject;
public StockObserver2(String name,Subject subject) {
super();
this.name = name;
this.subject = subject;
}
@Override
public void update() {
System.out.println(subject.getAction()+","+name+"關閉NBA直播,繼續工作!");
}
}

通知者抽象類
//通知者抽象類
public abstract class Subject {
String action;
private List<Observer> observers = new ArrayList<Observer>();
//添加同事
public abstract void attach(Observer observer);
//待老板來時,前臺通過電話通知所有同事
public abstract void notifyObserver();
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
}
通知者實現類:
//前臺類
public class Secretary extends Subject{
private List<Observer> observers = new ArrayList<Observer>();
private String action;
//添加同事
public void attach(StockObserver observer){
observers.add(observer);
}
//待老板來時,前臺通過電話通知所有同事
public void notifyObserver(){
for (Observer o : observers) {
o.update();
}
}
@Override
public void attach(Observer observer) {
observers.add(observer);
}
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
}

主程序:
public class Main {
public static void main(String[] args) {
//前臺小姐通知者
Secretary tongzhizhe = new Secretary();
//兩位公司同事
Observer tongshi1 = new StockObserver("魏關姹",tongzhizhe);
Observer tongshi2 = new StockObserver2("易管查",tongzhizhe);
//前臺幾下兩位同事
tongzhizhe.attach(tongshi1);
tongzhizhe.attach(tongshi2);
//老板來了.前臺通知同事
tongzhizhe.setAction("老板來了");
tongzhizhe.notifyObserver();
}
}

觀察者模式定義:

觀察者模式又叫做發布-訂閱(Publish-Subscribe)模式,它定義了一種一對多的依賴關系,讓多個觀察者對象同時監聽某一個主題對象。這個主題對象在發生狀態變化時,會通知所有觀察者對象,使他們能夠自動更新自己。

觀察者模式UML類圖:




觀察者模式特點:

適用場景
1) 當一個抽象模型有兩個方面, 其中一個方面依賴于另一方面。將這二者封裝在獨立的對象中以使它們可以各自獨立地改變和復用。
2) 當對一個對象的改變需要同時改變其它對象, 而不知道具體有多少對象有待改變。
3) 當一個對象必須通知其它對象,而它又不能假定其它對象是誰。換言之, 你不希望這些對象是緊密耦合的。

-------------------------------------------分割線-----------------------------------------------------------
后面內容摘自博客http://www.cnblogs.com/java-my-life/archive/2012/05/16/2502279.html

推模型和拉模型

  在觀察者模式中,又分為推模型和拉模型兩種方式。

  ●  推模型

     主題對象向觀察者推送主題的詳細信息,不管觀察者是否需要,推送的信息通常是主題對象的全部或部分數據。

  ●  拉模型

     主題對象在通知觀察者的時候,只傳遞少量信息。如果觀察者需要更具體的信息,由觀察者主動到主題對象中獲取,

相當于是觀察者從主題對象中拉數據。一般這種模型的實現中,會把主題對象自身通過update()方法傳遞給觀察者,這樣在觀察者需要獲取數據的時候,

就可以通過這個引用來獲取了。

  根據上面的描述,發現前面的例子就是典型的推模型,下面給出一個拉模型的實例。

  拉模型的抽象觀察者類

  拉模型通常都是把主題對象當做參數傳遞。

復制代碼
public interface Observer {/*** 更新接口* @param subject 傳入主題對象,方面獲取相應的主題對象的狀態*/public void update(Subject subject);
}
復制代碼

  拉模型的具體觀察者類

復制代碼
public class ConcreteObserver implements Observer {//觀察者的狀態private String observerState;@Overridepublic void update(Subject subject) {/*** 更新觀察者的狀態,使其與目標的狀態保持一致*/observerState = ((ConcreteSubject)subject).getState();System.out.println("觀察者狀態為:"+observerState);}}
復制代碼

  拉模型的抽象主題類

  拉模型的抽象主題類主要的改變是nodifyObservers()方法。在循環通知觀察者的時候,也就是循環調用觀察者的update()方法的時候

,傳入的參數不同了。

復制代碼
public abstract class Subject {/*** 用來保存注冊的觀察者對象*/private    List<Observer> list = new ArrayList<Observer>();/*** 注冊觀察者對象* @param observer    觀察者對象*/public void attach(Observer observer){list.add(observer);System.out.println("Attached an observer");}/*** 刪除觀察者對象* @param observer    觀察者對象*/public void detach(Observer observer){list.remove(observer);}/*** 通知所有注冊的觀察者對象*/public void nodifyObservers(){for(Observer observer : list){observer.update(this);}}
}
復制代碼

  拉模型的具體主題類

  跟推模型相比,有一點變化,就是調用通知觀察者的方法的時候,不需要傳入參數了。

復制代碼
public class ConcreteSubject extends Subject{private String state;public String getState() {return state;}public void change(String newState){state = newState;System.out.println("主題狀態為:" + state);//狀態發生改變,通知各個觀察者this.nodifyObservers();}
}
復制代碼

  兩種模式的比較

  ■  推模型是假定主題對象知道觀察者需要的數據;而拉模型是主題對象不知道觀察者具體需要什么數據,沒有辦法的情況下,干脆把自身傳遞

給觀察者,讓觀察者自己去按需要取值。

  ■  推模型可能會使得觀察者對象難以復用,因為觀察者的update()方法是按需要定義的參數,可能無法兼顧沒有考慮到的使用情況。這就意味

著出現新情況的時候,就可能提供新的update()方法,或者是干脆重新實現觀察者;而拉模型就不會造成這樣的情況,因為拉模型下,update()方法的

參數是主題對象本身,這基本上是主題對象能傳遞的最大數據集合了,基本上可以適應各種情況的需要。


JAVA提供的對觀察者模式的支持

  在JAVA語言的java.util庫里面,提供了一個Observable類以及一個Observer接口,構成JAVA語言對觀察者模式的支持。

  Observer接口

  這個接口只定義了一個方法,即update()方法,當被觀察者對象的狀態發生變化時,被觀察者對象的notifyObservers()方法就會調用這一方法。

public interface Observer {void update(Observable o, Object arg);
}

  Observable類

  被觀察者類都是java.util.Observable類的子類。java.util.Observable提供公開的方法支持觀察者對象,這些方法中有兩個對Observable的子類非常

重要:一個是setChanged(),另一個是notifyObservers()。第一方法setChanged()被調用之后會設置一個內部標記變量,代表被觀察者對象的狀態發生

了變化。第二個是notifyObservers(),這個方法被調用時,會調用所有登記過的觀察者對象的update()方法,使這些觀察者對象可以更新自己。

復制代碼
public class Observable {private boolean changed = false;private Vector obs;/** Construct an Observable with zero Observers. */public Observable() {obs = new Vector();}/*** 將一個觀察者添加到觀察者聚集上面*/public synchronized void addObserver(Observer o) {if (o == null)throw new NullPointerException();if (!obs.contains(o)) {obs.addElement(o);}}/*** 將一個觀察者從觀察者聚集上刪除*/public synchronized void deleteObserver(Observer o) {obs.removeElement(o);}public void notifyObservers() {notifyObservers(null);}/*** 如果本對象有變化(那時hasChanged 方法會返回true)* 調用本方法通知所有登記的觀察者,即調用它們的update()方法* 傳入this和arg作為參數*/public void notifyObservers(Object arg) {Object[] arrLocal;synchronized (this) {if (!changed)return;arrLocal = obs.toArray();clearChanged();}for (int i = arrLocal.length-1; i>=0; i--)((Observer)arrLocal[i]).update(this, arg);}/*** 將觀察者聚集清空*/public synchronized void deleteObservers() {obs.removeAllElements();}/*** 將“已變化”設置為true*/protected synchronized void setChanged() {changed = true;}/*** 將“已變化”重置為false*/protected synchronized void clearChanged() {changed = false;}/*** 檢測本對象是否已變化*/public synchronized boolean hasChanged() {return changed;}/*** Returns the number of observers of this <tt>Observable</tt> object.** @return  the number of observers of this object.*/public synchronized int countObservers() {return obs.size();}
}
復制代碼

  這個類代表一個被觀察者對象,有時稱之為主題對象。一個被觀察者對象可以有數個觀察者對象,每個觀察者對象都是實現Observer接口的對象。

在被觀察者發生變化時,會調用Observable的notifyObservers()方法,此方法調用所有的具體觀察者的update()方法,從而使所有的觀察者都被通知更

新自己。

怎樣使用JAVA對觀察者模式的支持

  這里給出一個非常簡單的例子,說明怎樣使用JAVA所提供的對觀察者模式的支持。在這個例子中,被觀察對象叫做Watched;而觀察者對象叫做

Watcher。Watched對象繼承自java.util.Observable類;而Watcher對象實現了java.util.Observer接口。另外有一個Test類扮演客戶端角色。

  源代碼

  被觀察者Watched類源代碼

復制代碼
public class Watched extends Observable{private String data = "";public String getData() {return data;}public void setData(String data) {if(!this.data.equals(data)){this.data = data;setChanged();}notifyObservers();}    
}
復制代碼

?

  觀察者類源代碼

復制代碼
public class Watcher implements Observer{public Watcher(Observable o){o.addObserver(this);}@Overridepublic void update(Observable o, Object arg) {System.out.println("狀態發生改變:" + ((Watched)o).getData());}}
復制代碼

  測試類源代碼

復制代碼
public class Test {public static void main(String[] args) {//創建被觀察者對象Watched watched = new Watched();//創建觀察者對象,并將被觀察者對象登記Observer watcher = new Watcher(watched);//給被觀察者狀態賦值watched.setData("start");watched.setData("run");watched.setData("stop");}}
復制代碼

  Test對象首先創建了Watched和Watcher對象。在創建Watcher對象時,將Watched對象作為參數傳入;然后Test對象調用Watched對象的

setData()方法,觸發Watched對象的內部狀態變化;Watched對象進而通知實現登記過的Watcher對象,也就是調用它的update()方法。

轉載于:https://www.cnblogs.com/xsyfl/p/6842511.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/371051.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/371051.shtml
英文地址,請注明出處:http://en.pswp.cn/news/371051.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

解決高度塌陷

<!DOCTYPE html> <html lang"en" dir"ltr"><head><meta charset"utf-8"><title>高度塌陷解決</title><style media"screen">.box1{border: 10px #bfc993 solid;}.box2{width: 100px;height…

IBM AIX:Java進程大小監視

本文將為您提供有關如何計算在IBM AIX 5.3 OS上運行的Java VM進程的Java進程大小內存占用量的快速參考指南。 這是我關于該主題的原始文章的補充文章&#xff1a; 如何在AIX上監視Java本機內存 。 我強烈建議所有參與生產支持或AIX上部署Java應用程序開發的人員閱讀此書。 為…

java 饑餓現象,Java單例模式、饑餓模式代碼實例

class MyThreadScopeData {// 單例private MyThreadScopeData() {}// 提供獲取實例方法public static synchronized MyThreadScopeData getThreadInstance() {// 從當前線程范圍內數據集中獲取實例對象MyThreadScopeData instance map.get();if (instance null) {instance n…

12. 抽象與密封

一、抽象類與抽象方法 1、抽象類與抽象方法聲明&#xff1a; 抽象類&#xff1a;在面向對象的概念中&#xff0c;所有的類都是通過對象來描述&#xff0c;但并不是所有的類都用來描述對象。如果一個類中沒有足夠的信息來描繪一個具體的對象&#xff0c;這樣的類就是抽象類。  …

pstate0 vid數值意義_天體運動的簡單數值計算

&#xff08;建議閱讀全文&#xff09; 預備知識 萬有引力&#xff0c; 彈簧振子受迫運動的簡單數值計算    下面我們來用一種極其簡單的算法對單個天體在中心天體的萬有引力作用下的運動進行數值計算&#xff0e; 事實上該問題存在解析解&#xff08;見開普勒三定律&#x…

集合框架

集合框架包含的內容&#xff1a; 集合框架的接口&#xff1a; List接口實現類 ArrayList 1 package com.jredu.ch01;3 import java.util.ArrayList;5 import java.util.List;7 public class ArrayListTest {9 public static void main(String[] args) { 10 // TODO…

使用CSS實現無滾動條滾動

我們都知道&#xff0c;擼頁面的時候當我們的內容超出了我們的div&#xff0c;往往會出現滾動條&#xff0c;影響美觀。 尤其是當我們在做一些導航菜單的時候。滾動條一出現就破壞了UI效果。 我們不希望出現滾動條&#xff0c;也不希望超出去的內容被放逐&#xff0c;就要保留…

Java中的類型安全的空集合

我之前曾在Java Collections類的實用程序上進行過博客撰寫&#xff0c;并且特別地在使用Usings Collections Methods上的博客emptyList&#xff08;&#xff09;&#xff0c;emptyMap&#xff08;&#xff09;和emptySet&#xff08;&#xff09;上進行了博客撰寫。 在本文中&a…

php cpu mac,PHP 獲得計算機的唯一標識[CPU,網卡 MAC地址]

//獲取電腦的CPU信息function OnlyU(){$a ;$b array();if(function_exists(exec)){if(mailto:!exec( /all",$b)){return false;}}elseif(function_exists(system)){ob_start();if(mailto:!system( /all")){return false;}else{}$b ob_get_contents();ob_end_clean…

劍指offer二十二之從上往下打印二叉樹

一、題目 從上往下打印出二叉樹的每個節點&#xff0c;同層節點從左至右打印。 二、思路 二叉樹的層次遍歷&#xff0c;可以借助隊列實現。具體思路詳見注釋。 三、代碼 import java.util.ArrayList; import java.util.LinkedList; /** public class TreeNode {int val 0;Tree…

arduino i2c 如何寫16位寄存器_arduino入門

硬件&#xff1a;Arduino Uno是基于ATmega328P(數據表)的微控制器板。它具有14個數字輸入/輸出引腳(其中6個可用作PWM輸出)&#xff0c;6個模擬輸入&#xff0c;工作電壓5v&#xff0c;輸入電壓7-12v。串行&#xff1a;0(RX)和1(TX)用于接收(RX)和發送(TX)TTL串行數據。這些引腳…

原生JS實現banner圖的滾動與跳轉

HTML部分&#xff1a; <div id"banner"><!--4張滾動的圖片--><div id"inside"><img src"../../img/14072415363339_0.jpg"><img src"../../img/14072415383924_0.jpg" id"img2" /><img sr…

Java中的緊湊堆外結構/組合

在上一篇文章中&#xff0c;我詳細介紹了代碼對主內存的訪問方式的含義。 從那時起&#xff0c;我對使用Java可以做什么以實現更可預測的內存布局有很多疑問。 有些模式可以使用數組支持的結構來應用&#xff0c;我將在另一篇文章中討論。 這篇文章將探討如何模擬Java中非常缺少…

java字符集編碼是,java字符集與編碼有關問題

java字符集與編碼問題沒想到自己的第一篇javaeye博客就是讓人頭痛的java字符集轉碼問題&#xff0c;下面是我個人的一些認識與網上收集的代碼。在java中String在JVM里是unicode的&#xff0c;任何byte[]到String以及String到byte[]都涉及到字符集編碼轉換。基本規則是&#xff…

mysql序列號生成_一文看懂mycat的6種全局序列號實現方式

概述在實現分庫分表的情況下&#xff0c;數據庫自增主鍵已無法保證自增主鍵的全局唯一。為此&#xff0c;MyCat 提供了全局sequence&#xff0c;并且提供了包含本地配置和數據庫配置等多種實現方式。下面對這幾種實現方式做一下介紹。1、本地文件方式原理&#xff1a;此方式 My…

android.graphics.Paint方法setXfermode (Xfermode x...

[java] view plaincopymPaint new Paint(); mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SCREEN)); 常見的Xfermode&#xff08;SRC為原圖&#xff0c;DST為目標圖&#xff09;&#xff0c;把代碼中的SRC_IN換成下圖指定的模式就會出現對應的效果圖…

從零開始的全棧工程師——html篇1

全棧工程師也可以叫web 前端 H5主要是網站 app 小程序 公眾號這一塊 HTML篇 html(超文本標記語言&#xff0c;標記通用標記語言下的一個應用。) “超文本”就是指頁面內可以包含圖片、鏈接&#xff0c;甚至音樂、程序等非文字元素。 超文本標記語言的結構包括“頭”部分&am…

二分+樹的直徑 [Sdoi2011]消防

問題 D: [Sdoi2011]消防 時間限制: 1 Sec 內存限制: 512 MB 提交: 12 解決: 6 [提交][狀態][討論版] 題目描述 某個國家有n個城市&#xff0c;這n個城市中任意兩個都連通且有唯一一條路徑&#xff0c;每條連通兩個城市的道路的長度為zi(zi<1000)。 這個國家的人對火焰…

使用MRUnit測試Hadoop程序

這篇文章將略微繞開使用MapReduce實現數據密集型處理中的模式&#xff0c;以討論同樣重要的測試。 湯姆?惠勒 &#xff08; Tom Wheeler&#xff09;在紐約2012年Strata / Hadoop World會議上參加的一次演講給了我部分啟發。 處理大型數據集時&#xff0c;想到的并不是單元測試…

android之 TextWatcher的監聽

以前用過android.text.TextWatcher來監聽文本發生變化&#xff0c;但沒有仔細去想它&#xff0c;今天興致來了就發個瘋來玩玩吧&#xff01; 有點擔心自己理解錯&#xff0c;所以還是先把英文API解釋給大家看看 1、什么情況下使用了&#xff1f; When an object of a type is a…