1.描述java
定義對象間的一種一對多的依賴關係,當一個對象的狀態發生變化時,全部依賴他的對象都收到通知並被自動更新。程序員
2.優勢this
·具體主題和具體觀察者之間是鬆耦合關係。因爲主題(Subject)接口僅僅依賴觀察者(Observer)接口,所以具體主題只是知道他的具體觀察者是實現某個觀察者接口的類的實例,但不須要知道具體是那個類。一樣,因爲觀察者僅僅依賴主題接口,所以具體觀察者只是知道他依賴的主題是實現主題接口的某個類的實例,但不須要知道具體是那個類。spa
·觀察者模式知足「開閉原則」設計
3.用途3d
·當一個的數據更新時須要通知其餘對象,但這個對象又不但願和須要被通知的對象造成緊耦合。code
·當一個對象的數據更新時,這個對象須要其餘對象也各自更新本身的數據,但這個對象不知道具體有多少對象須要更新數據。server
4.模式的使用對象
·主題(Subject):主題是一個接口,該接口規定了具體主題須要實現的方法。(添加、刪除、通知觀察者更新數據)blog
·觀察者(Observer):觀察者是一個接口,該接口規定了具體觀察者用來實現更新數據的方法。
·具體主題(ConcreteSubject):具體主題是實現主題接口類的一個實例,該實例能夠包含常常變化的數據。具體主題須要使用一個集合,存放觀察者的引用,一遍數據變化時通知觀察者更新數據。
·具體觀察者(ConcreteObserver):具體觀察者是實現觀察者接口的類的一個實例。具體觀察者包含能夠存放具體主題引用的主題接口變量,以便具體觀察者讓具體主題將本身的引用添加到主題主題的集合中,是本身成爲他的觀察者;或從具體主題中刪除本身,是本身再也不是觀察者。
5.UML圖
6.案例
案例1:一個學生(Student)關注求職中心(Center)的求職信息,在求職中心發佈新的招聘信息是,學生要及時得到信息。
代碼:
1 package 觀察者模式.test1; 2 3 /** 4 * 主題 5 */ 6 public interface Subject { 7 public void addObserver(Observer o); 8 public void deleteObserver(Observer o); 9 public void notifyObservers(); 10 } 11 12 13 package 觀察者模式.test1; 14 15 /** 16 * 觀察者 17 */ 18 public interface Observer { 19 public void observe(String mess); 20 } 21 22 23 package 觀察者模式.test1; 24 25 import java.util.ArrayList; 26 27 /** 28 * 具體主題 29 */ 30 public class JobCenter implements Subject { 31 String mess; //信息 32 boolean changed; 33 ArrayList<Observer> personList; //存放觀察者引用 34 JobCenter(){ 35 personList = new ArrayList<Observer>(); 36 mess = ""; 37 changed = false; 38 } 39 public void addObserver(Observer o) { 40 if(!(personList.contains(o))) 41 personList.add(o); 42 } 43 44 public void deleteObserver(Observer o) { 45 if(!(personList.contains(o))) 46 personList.remove(o); 47 } 48 49 public void notifyObservers() { 50 if(changed) 51 for(Observer o : personList) 52 o.observe(mess); 53 changed = false; 54 } 55 56 public void giveNewMess(String str){ 57 if(str.equals(mess)) 58 changed = false; 59 else{ 60 mess = str; 61 changed = true; 62 } 63 } 64 } 65 66 67 package 觀察者模式.test1; 68 69 /** 70 * 具體觀察者 71 */ 72 public class Student implements Observer { 73 Subject subject; 74 public Student(Subject subject) { 75 this.subject = subject; 76 subject.addObserver(this); 77 } 78 79 public void observe(String mess) { 80 System.out.println("我是Student,觀察以下內容:" + "\n" + mess); 81 } 82 83 } 84 85 86 package 觀察者模式.test1; 87 88 public class test { 89 90 public static void main(String[] args) { 91 JobCenter center = new JobCenter();//創建具體主題 92 Student s1 = new Student(center);//創建具體觀察者 93 center.giveNewMess("騰訊須要10個JAVA程序員"); 94 center.notifyObservers(); 95 center.giveNewMess("阿里須要9個JAVA工程師"); 96 center.notifyObservers(); 97 } 98 99 }
案例2:觀察者模式中的「推數據」和「拉數據」
·推數據方式
推數據方式是指具體主題變化後的數據所有交給具體觀察者,即將變化後的數據傳遞給觀察者用於更新數據。當具體主題知道具體觀察者須要哪些數據時使用推數據方式。
·拉數據方式
拉數據方式是指主題數據變化後不將數據傳遞給具體觀察者,而是提供得到這些數據的方法,觀察者調用這些方法獲得數據,須要本身判斷數據是否發生變化。當具體主題不知道具體觀察者須要哪些數據時,使用拉數據方式。
一家商店(ShopSubject)天天發佈當天打折商品的名字,打折先後的價格。兩位顧客(Observer)對此感興趣,其中一位只關心打折商品的名稱,另外一位只關心打折先後的價格。
代碼:
1 package 觀察者模式.test2; 2 3 /** 4 * 主題 5 */ 6 public interface Subject { 7 public void addObserver(Observer o); 8 public void deleteObserver(Observer o); 9 public void notifyObservers(); 10 } 11 12 13 package 觀察者模式.test2; 14 15 /** 16 * 觀察者 17 */ 18 public interface Observer { 19 public void update(); 20 } 21 22 23 package 觀察者模式.test2; 24 25 import java.util.ArrayList; 26 27 /* 28 * 具體主題 29 */ 30 public class ShopSubject implements Subject { 31 String goodsName; 32 double oldPrice; 33 double newPrice; 34 ArrayList<Observer> customerList; 35 ShopSubject(){ 36 this.customerList = new ArrayList<Observer>(); 37 } 38 public void addObserver(Observer o) { 39 if(!customerList.contains(o)) 40 customerList.add(o); 41 } 42 43 public void deleteObserver(Observer o) { 44 if(customerList.contains(o)) 45 customerList.remove(o); 46 } 47 48 public void notifyObservers() { 49 for(Observer o : customerList) 50 o.update(); //然觀察者執行更新操做,不提供數據 51 } 52 53 public void setDiscountGoods(String name, double oldPrice, double newPrice){ 54 goodsName = name; 55 this.oldPrice = oldPrice; 56 this.newPrice = newPrice; 57 this.notifyObservers(); 58 } 59 public String getGoodsName() { 60 return goodsName; 61 } 62 63 public double getOldPrice() { 64 return oldPrice; 65 } 66 67 public double getNewPrice() { 68 return newPrice; 69 } 70 71 } 72 73 74 package 觀察者模式.test2; 75 76 /* 77 * 具體觀察者1 78 */ 79 public class Customer1 implements Observer { 80 Subject subject; 81 String goodsName, personName; 82 Customer1(Subject subject, String personName){ 83 this.subject = subject; 84 this.personName = personName; 85 subject.addObserver(this); 86 } 87 public void update() { 88 if(subject instanceof ShopSubject){ 89 this.goodsName = ((ShopSubject)subject).getGoodsName(); 90 System.out.println(this.personName + "關心打折的商品名字:" + goodsName); 91 } 92 } 93 94 } 95 96 /* 97 * 具體觀察者2 98 */ 99 class Customer2 extends Customer1{ 100 double oldPrice; 101 double newPrice; 102 Customer2(Subject subject, String personName) { 103 super(subject, personName); 104 } 105 public void update() { 106 if(subject instanceof ShopSubject){ 107 this.oldPrice = ((ShopSubject)subject).getOldPrice(); 108 this.newPrice = ((ShopSubject)subject).getNewPrice(); 109 System.out.println(this.personName + "關心商品打折前的價格:" + oldPrice); 110 System.out.println(this.personName + "關心商品打折後的價格:" + newPrice); 111 } 112 } 113 } 114 115 116 package 觀察者模式.test2; 117 118 public class test { 119 120 public static void main(String[] args) { 121 ShopSubject shop = new ShopSubject(); 122 Customer1 c1 = new Customer1(shop, "張三"); 123 Customer2 c2 = new Customer2(shop, "李四"); 124 shop.setDiscountGoods("iPhone7", 8000, 7000); 125 shop.setDiscountGoods("小米4", 4000, 3000); 126 } 127 128 }
案例3:觀察者與多主題
一個觀察者能夠依賴多個主題,在種狀況下,使用拉數據方式。
李先生(Observer)但願知道氣象站(WeatherStation)每日的天氣數據和旅行社(TravelAgency)的旅行信息。
代碼:
1 package 觀察者模式.test3; 2 3 import java.util.ArrayList; 4 5 public class test { 6 7 public static void main(String[] args) { 8 WeatherStation w = new WeatherStation(); 9 TravelAgency t = new TravelAgency(); 10 Person p = new Person(w, t); 11 w.giveMess("10月2日", "陰有小雨", 28, 20); 12 t.giveMess("10月3日", "長城1日遊"); 13 14 } 15 16 } 17 18 /** 19 * 主題 20 */ 21 interface Subject { 22 public void addObserver(Observer o); 23 public void deleteObserver(Observer o); 24 public void notifyObservers(); 25 } 26 27 /** 28 * 觀察者 29 */ 30 interface Observer { 31 public void update(Subject subject); 32 } 33 34 class Theme implements Subject{ 35 private ArrayList<Observer> personList; 36 Theme(){ 37 this.personList = new ArrayList<Observer>(); 38 } 39 public void addObserver(Observer o) { 40 if(!(personList.contains(o))) 41 personList.add(o); 42 if(o == null) 43 return; 44 } 45 46 public void deleteObserver(Observer o) { 47 if(!(personList.contains(o))) 48 personList.remove(o); 49 } 50 51 public void notifyObservers() { 52 for(Observer o : personList) 53 o.update(this); 54 } 55 56 } 57 /* 58 * 具體觀察者,天氣預報中心 59 */ 60 class WeatherStation extends Theme{ 61 private String forecastTime, forecastMess; 62 private int maxTemperature, minTemperature; 63 64 public void giveMess(String t, String mess, int max, int min){ 65 this.forecastTime = t; 66 this.forecastMess = mess; 67 this.maxTemperature = max; 68 this.minTemperature = min; 69 this.notifyObservers(); 70 } 71 72 public String getForecastTime() { 73 return forecastTime; 74 } 75 76 public String getForecastMess() { 77 return forecastMess; 78 } 79 80 public int getMaxTemperature() { 81 return maxTemperature; 82 } 83 84 public int getMinTemperature() { 85 return minTemperature; 86 } 87 } 88 89 /* 90 * 具體主題,旅遊部門 91 */ 92 class TravelAgency extends Theme{ 93 private String tourStartTime,mess; 94 95 public String getTourStartTime() { 96 return tourStartTime; 97 } 98 99 public String getMess() { 100 return mess; 101 } 102 103 public void giveMess(String time, String mess){ 104 this.tourStartTime = time; 105 this.mess = mess; 106 this.notifyObservers(); 107 } 108 } 109 110 /* 111 * 具體觀察者 112 */ 113 class Person implements Observer{ 114 Subject s1,s2; 115 private String forecastTime, forecastMess; 116 private int maxTemperature, minTemperature; 117 private String tourStartTime,mess; 118 Person(Subject s1, Subject s2){ 119 this.s1 = s1; 120 this.s2 = s2; 121 s1.addObserver(this); 122 s2.addObserver(this); 123 } 124 public void update(Subject subject) { 125 if(subject instanceof WeatherStation){ 126 this.forecastTime = ((WeatherStation)subject).getForecastTime(); 127 this.forecastMess = ((WeatherStation)subject).getForecastMess(); 128 this.maxTemperature = ((WeatherStation)subject).getMaxTemperature(); 129 this.minTemperature = ((WeatherStation)subject).getMinTemperature(); 130 System.out.println("天氣預報日期:" + forecastTime + "\t天氣情況:" + forecastMess + "\t高該溫度:" + maxTemperature + "\t最低溫度:" + minTemperature); 131 } 132 if(subject instanceof TravelAgency){ 133 this.tourStartTime = ((TravelAgency)subject).getTourStartTime(); 134 this.mess = ((TravelAgency)subject).getMess(); 135 System.out.println("旅遊開始日期:" + tourStartTime + "\t旅遊信息:" + mess); 136 } 137 } 138 }
7.JAVA API中的Observable類和Observer接口
·做用:
因爲觀察者模式是JAVA程序設計中經常使用的模式之一,java.util包提供了用來設計符合觀察者模式的Observable類和Observer接口。其中Observable類的子類稱做一個具體的「可觀察者」,Observer接口與上文所述的觀察者接口相同。
·優勢
使用觀察者模式以前,統一使用java.util包中的Observable類和Observer接口未來有利於系統間的複用,避免了不一樣開發人員開發不一樣接口帶來的麻煩。
·缺點
Observable是一個類不是一個接口,他的子類沒法經過繼承複用其餘類的方法。
這個本身在網上搜案例吧。