-
觀察者缺點: 可能會引起無謂的操作: 由于被觀察者每次都會進行廣播通信,不管觀察者是否需要該信息,每個觀察者都會被調用update方法.如果觀察者不需要執行相應的處理,那么此處操作就浪費了. (浪費的是性能問題,最怕引起誤更新,即忘了刪除某個觀察者,以至于更新了本來不需更新信息的觀察者).查看全部
-
觀察者優點: 動態聯動就是:做一個操作會引起其他相關操作.查看全部
-
測試類查看全部
-
具體觀察者查看全部
-
JAVA提供的對觀察者模式的支持 步驟: 1.創建一個具體主題角色類繼承Observable類,類中定義一個變量存放具體主題角色的狀態信息. 生成set與get方法,通知方法在Observable中已經實現了,在set()方法中調用了setChanged()方法后,根據情況需要選擇是否調用帶參的notifyObservers方法. 可以使用推模型或拉模型,即當notifyObservers()方法無參時,使用拉模型. 當notifyObservers()方法有參時,則使用推模型. 2.創建一個具體觀察者角色類實現Observer接口.Observer接口聲明了update(Observable o1,Object o2)方法.Observable類型的參數為了支持拉模型的實現方式,Object類型的參數是為了支持推模型的實現方式. 具體觀察者角色類中應定義一個變量存放具體觀察者角色的狀態信息與存放觀察者個人信息的變量,并實現update方法. 3.創建測試類,首先創建一個具體主題角色的對象,創建任意個具體觀察者角色對象并初始化個人信息,然后使用具體主題角色繼承Observable類的addObserver(Observer o)方法注冊觀察者.最后調用具體主題角色的set方法更新狀態信息. notifyObservers()與notifyObservers(Object obj)方法的區別, notifyObservers()方法內部會調用Observer接口聲明的update(Observable obj1 ,Object obj2)方法,把 this當前對象作為update方法的第一個參數,而將第二個參數設置為null. notifyObservers(Object obj)內部也調用Observer接口聲明的update方法,并把this當前對象作外update方法的 第一個參數,將notifyObservers方法的參數作為update方法的第二個參數. 所以在Observer接口聲明的update方法中都能使用Observale類型的參數,至于update方法中的Object類型參數是否有值 取決于是否使用帶參的notifyObservers方法,也就是是否使用推模型.查看全部
-
Observable類對notifyObservers()方法進行了重載,即notifyObservers()與notifyObservers(Object arg). 前者用于拉模型,后者用于推模型. 查看notifyObservers(Object 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); } 查看notifyObservers()源碼: public void notifyObservers() { notifyObservers(null); } 可以看到當使用notifyObservers(Object arg)方法時,即使用推模式,update方法中不僅把arg對象作為參數,而且會把this當前對象作為參數,當使用notifyObservers()方法時,內部直接調用notifyObservers(null),因此update方法有效參數只有this當前對象. 因此兩種notifyObservers方法都會把this當前對象作為update()方法的參數,即不管使用哪種模式,在具體觀察者中的update方法總可以通過Observable引用獲取得到具體主題角色對象.查看全部
-
JAVA提供的對觀察者模式的支持 在JAVA語言的java.util庫里面,提供了一個Observable類以及一個Observer接口,構成JAVA語言對觀察者模式的支持. Observable類實現了大部分抽象主題角色的功能,Observable類就相當于抽象主題角色.所有具體主題角色都要繼承它. Observer接口中聲明了一個update()方法,Java提供的Observer接口就相當于抽象觀察者角色. 使用JAVA提供對觀察者模式的實現方式與自己實現觀察者模式的對比: 1.不需要再定義觀察者和被觀察者的接口了,JDK幫忙定義了. 2.具體主題角色里面不需要再維護觀察者的注冊信息了,這個在JAVA中的Observable類里已經實現好了.使用該類定義的addObserver()方法注冊觀察者(因此通知的順序是不確定的). 3.觸發通知時要先調用Observable類中定義的setChanged()方法,再調用notifyObservers()方法,setChanged()方法是JAVA為了幫助實現更精確的觸發控制而提供的功能. 4.具體觀察者的實現里面,update()方法能同時支持推模型與拉模型.查看全部
-
觀察者實現的兩種方式: 在觀察者模式中,又分為拉模型和推模型兩種方式. 拉模型:主題對象在通知觀察者的時候,只傳遞少量信息.如果觀察者需要更具體的信息,由觀察者主動到主題對象中獲取,相當于是觀察者從主題對象中拉數據. 一般這種模型的實現中,會把主題對象自身通過update()方法傳遞給觀察者,這樣在觀察者需要獲取數據的時候,就可以通過這個引用來獲取了. 推模型:主題對象向觀察者推送主題的詳細信息,不管觀察者是否需要.推送的信息通常是主題對象的全部或部分數據. 前面的例子就是典型的拉模型 拉模型: 在抽象觀察者聲明的update()方法中需要定義抽象具體主題類型的參數. 在具體觀察者實現的update()方法中直接通過引用(強轉為某個具體主題角色)獲取得到某個具體主題角色的狀態信息,并賦值給用來存放具體觀察者狀態的變量. 具體觀察者: private String state; public void update(Subject subject){ state=((ConcreteSubject)subject).getSubjectState(); } 抽象主題中的通知觀察者方法,不需要傳入參數,即抽象主題的通知notify()方法不需要提供參數,因為update()方法中直接使用this關鍵字傳入當前對象. 抽象主題: public void nodifyObservers(){ for(Observer observer : list){ observer.update(this); } } 兩種模型比較: 推模型是假定目標對象知道觀察者需要的數據. 拉模型是目標對象不知道觀察者具體需要什么數據,因此把自身傳給觀察者,由觀察者來取值. 推模型會使觀察者難以復用. 拉模型下,update方法的參數是目標對象本身,甚至上可以適應各種情景需要.查看全部
-
堆模型: 在抽象觀察者聲明的update()方法中,需要提供字符串類型的參數. 在具體觀察者實現的update()方法中直接通過參數獲取得到某個具體主題角色的狀態信息,并賦值給用來存放具體觀察者狀態的變量. 具體觀察者; private String state; public void update(String newState){ state=newState; } 抽象主題中的通知觀察者方法,傳入的是具體主題的字符串狀態信息,因此抽象主題的通知notify()方法中需要提供字符串類型的參數. 抽象主題: public void nodifyObservers(String newState){ for(Observer observer : list){ observer.update(newState); } }查看全部
-
拉模型: 在抽象觀察者聲明的update()方法中需要定義抽象具體主題類型的參數. 在具體觀察者實現的update()方法中直接通過引用(強轉為某個具體主題角色)獲取得到某個具體主題角色的狀態信息,并賦值給用來存放具體觀察者狀態的變量. 具體觀察者: private String state; public void update(Subject subject){ state=((ConcreteSubject)subject).getSubjectState(); } 抽象主題中的通知觀察者方法,不需要傳入參數,即抽象主題的通知notify()方法不需要提供參數,因為update()方法中直接使用this關鍵字傳入當前對象. 抽象主題: public void nodifyObservers(){ for(Observer observer : list){ observer.update(this); } }查看全部
-
觀察者實現的兩種方式: 在觀察者模式中,又分為拉模型和推模型兩種方式. 拉模型:主題對象在通知觀察者的時候,只傳遞少量信息.如果觀察者需要更具體的信息,由觀察者主動到主題對象中獲取,相當于是觀察者從主題對象中拉數據. 一般這種模型的實現中,會把主題對象自身通過update()方法傳遞給觀察者,這樣在觀察者需要獲取數據的時候,就可以通過這個引用來獲取了. 推模型:主題對象向觀察者推送主題的詳細信息,不管觀察者是否需要.推送的信息通常是主題對象的全部或部分數據. 前面的例子就是典型的拉模型查看全部
-
觀察者模式的調用順序示意圖. List<String> list =new ArrayList<String>(); list.add("1"); list.add("2"); list.add("3"); for(String str:list){ System.out.println(str); } 運行結果為1 2 3 如果抽象主題使用List集合來注冊觀察者列表,那么測試類中具體主題實例就會使用List集合來注冊觀察者,然后當具體主題角色設置狀態信息后就會調用notify()方法,方法里循環遍歷觀察者列表,并進行通知,那么通知的順序就是注冊觀察者時的順序. 如果抽象主題角色使用set、map集合來存儲觀察者列表,那么測試類中具體主題實例就會使用set或map集合來注冊觀察者. 當具體主題角色設置狀態信息后會通知所有觀察者,通知的順序是不確定的. 如果使用JAVA對觀察者模式的支持來實現觀察者模式,因為是使用addObserver()方法注冊觀察者,并不能確定遍歷時通知的順序. 因此觀察者實現的功能不能依賴于通知的順序,也就是多個觀察者的通知順序是平行的,相互不應該有先后依賴的關系.查看全部
-
觸發通知Notify()方法的時機. 在實現觀察者模式的時候,一般情況下是完成了狀態維護后觸發通知,因為通知會傳遞數據(抽象主題循環遍歷調用update方法傳的參數為this,即傳遞具體主題角色對象),不能夠先通知后改變數據,會導致觀察者和具體主題角色的狀態不一致.查看全部
-
命名建議: 目標接口的定義,建議在名稱后面跟Subject 觀察者接口的定義,建議在名稱后面跟Observer 觀察者接口的更新方法,建議名稱為update,不限制參數類型與個數.查看全部
-
具體主題與觀察者的關系 具體主題可以只被一個觀察者觀察(一對一). 一個觀察者可以觀察多個具體主題(天氣與報紙).一般情況下,觀察者應為不同的具體主題角色定義不同的update()方法. 單向依賴:只有觀察者依賴具體主題角色,而不是具體主題角色依賴觀察者.主動權在具體主題角色上.查看全部
舉報
0/150
提交
取消