設計模式(二)——觀察者模式

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是一個類不是一個接口,他的子類沒法經過繼承複用其餘類的方法。

這個本身在網上搜案例吧。

相關文章
相關標籤/搜索