Java基础知识之设计模式--观察者模式

Java设计模式--观察者模式

声明:本文根据慕课网GerryZhang老师的精品课程整理来的:慕课网

 什么是设计模式(Design Pattern)?

  设计模式是一套被反复使用,多数人知晓的,经过分类编目的,代码设计经验的总结。

观察者模式的定义?

  定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于他的对象都得到通知,并被自动更新。

观察者模式的分类?

  1.推模型:目标对象主动向观察者推送目标的详细信息,推送的信息通常是目标对象的全部或部分数据,相当于广播通信

  2.拉模型:目标对象在通知观察者的时候,只传递少量信息。如果观察者需要更具体的信息,由观察者主动到目标对象中获取,相当于是观察者从目标对象中拉数据。一般这种模型的实现中,会把目标对象自身通过update方法传递给观察者。

Java中提供的观察者实现与自己实现的对比:

  1.不需要再定义观察者和目标的接口了,JDK帮忙定义了

  2.具体的目标实现里面不需要再维护观察者的注册信息了,这个在Java中的Observable类里面已经帮忙实现了。

  3.触发通知的方式有一些变化,要先调用setChanged方法,这个是Java为了帮助实现更精确的触发控制而提供的功能。

  4.具体观察者的实现里面,update方法其实能同时支持推模型和拉模型,这个是Java在定义的时候,就已经考虑进去了。

观察者模式的优点和缺点:

  优点:

    1.观察者模式实现了观察者和目标之间的抽象耦合。

    2.观察者模式实现了动态联动。

    3.观察者模式支持广播通信。

  缺点:

    可能会引起无谓的操作

在什么情况下使用观察者模式:

  1.当一个抽象模型有两个方面,其中一个方面的操作依赖于另一个方面的状态变化。

  2.如果在更改一个对象的时候,需要同时连带改变其他的对象,而且不知道究竟应该有多少对象需要被连带改变。

  3.当一个对象必须通知其他的对象,但你又希望这个对象和其他被通知的对象是松散耦合的。

推模型示例:

  1.创建观察者接口和目标对象

  

 1 /**
 2  * 这是一个观察者接口,定义一个更新的接口给那些在目标发生改变时被通知的对象
 3  * @author Administrator
 4  *
 5  */
 6 public interface Observer {
 7     /**
 8      * 更新的接口
 9      * @Description: TODO
10      * @param subject
11      * @returnType: void
12      */
13     public void update(WeatherSubject subject);
14 }
观察者接口
 1 /**
 2  * 目标对象,它知道观察它的观察者,并提供注册(添加)和删除观察者的接口。
 3  * @author Administrator
 4  *
 5  */
 6 public class WeatherSubject {
 7     // 用来保存注册的观察者对象
 8     List<Observer> observers = new ArrayList<Observer>();
 9 
10     /**
11      * 把订阅的人添加到订阅者列表中
12      */
13     public void attach(Observer observer) {
14         observers.add(observer);
15     }
16 
17     /**
18      * 从集合中删除观察者
19      */
20     public void detach(Observer observer) {
21         if (observers.contains(observer)) {
22             observers.remove(observer);
23         }
24     }
25 
26     /**
27      * 通知所有注册的观察者对象
28      */
29     protected void notifyObservers() {
30         for (Observer observer : observers) {
31             observer.update(this);
32         }
33     }
34 }
目标对象

  2.分别创建具体的目标对象和具体的观察者对象

 1 /**
 2  * 具体的目标对象,负责把有关状态存入到相应的观察者对象中
 3  * @author Administrator
 4  *
 5  */
 6 public class ConcreteWeatherSubject extends WeatherSubject {
 7     //获取天气的内容信息
 8     private String weatherContent;
 9 
10     /**
11      * @return the weatherContent
12      */
13     public String getWeatherContent() {
14         return weatherContent;
15     }
16 
17     /**
18      * @param weatherContent the weatherContent to set
19      */
20     public void setWeatherContent(String weatherContent) {
21         this.weatherContent = weatherContent;
22         //内容有了,说明天气更细了,通知所有的订阅人
23         this.notifyObservers();
24     }
25     
26 }
具体目标对象
 1 /**
 2  * 具体的观察者对象,实现更新的方法,使自身的状态和目标的状态保持一致
 3  * @author Administrator
 4  *
 5  */
 6 public class ConcreteObserver implements Observer {
 7     //观察者的名字,是谁收到了这个信息
 8     private String observerName;
 9     
10     //天气内容的情况,这个消息从目标处获取
11     private String weatherContent;
12     
13     //提醒的内容,根据不同的人提醒不同的信息
14     private String remindThing;
15     
16     /**
17      * 获取目标类的状态同步到观察者的状态中
18      */
19     @Override
20     public void update(WeatherSubject subject) {
21         weatherContent = ((ConcreteWeatherSubject)subject).getWeatherContent();
22         System.out.println(observerName+"收到了"+weatherContent+","+remindThing);
23     }
24 
25     /**
26      * @return the observerName
27      */
28     public String getObserverName() {
29         return observerName;
30     }
31 
32     /**
33      * @param observerName the observerName to set
34      */
35     public void setObserverName(String observerName) {
36         this.observerName = observerName;
37     }
38 
39     /**
40      * @return the weatherContent
41      */
42     public String getWeatherContent() {
43         return weatherContent;
44     }
45 
46     /**
47      * @param weatherContent the weatherContent to set
48      */
49     public void setWeatherContent(String weatherContent) {
50         this.weatherContent = weatherContent;
51     }
52 
53     /**
54      * @return the remindThing
55      */
56     public String getRemindThing() {
57         return remindThing;
58     }
59 
60     /**
61      * @param remindThing the remindThing to set
62      */
63     public void setRemindThing(String remindThing) {
64         this.remindThing = remindThing;
65     }
66     
67 }
具体观察者对象

  3.创建测试类进行测试

  程序运行逻辑(准备阶段):

    1.创建目标对象

    2.创建观察者对象

    3.向目标对象注册观察者对象

  程序性运行逻辑(运行阶段):

    1.改变目标对象的状态

    2.目标对象通知所有观察者对象运行相应的处理

    3.观察者对象回调目标对象,获取相应的数据

 1 public class Test {
 2 
 3     public static void main(String[] args) {
 4         //1.创建一个目标
 5         ConcreteWeatherSubject subject = new ConcreteWeatherSubject();
 6         
 7         //2.创建一个观察者
 8         ConcreteObserver girlObserver = new ConcreteObserver();
 9         girlObserver.setObserverName("黄明的女朋友");
10         girlObserver.setRemindThing("天气很好,适合约会");
11         
12         ConcreteObserver mumObserver = new ConcreteObserver();
13         mumObserver.setObserverName("黄明的老妈");
14         mumObserver.setRemindThing("天气很好,适合购物");
15         
16         //3.注册观察者
17         subject.attach(girlObserver);;
18         subject.attach(mumObserver);
19         
20         //4.目标发布天气
21         subject.setWeatherContent("明天天气晴朗,气温28度");
22     }
23 
24 }
测试类

拉模型示例:

  1.创建观察者接口和目标对象

 1 /**
 2  * 这是一个观察者接口,定义一个更新的接口给那些在目标发生改变时被通知的对象
 3  * @author Administrator
 4  *
 5  */
 6 public interface Observer {
 7     /**
 8      * 更新的接口
 9      * @Description: TODO
10      * @param subject
11      * @returnType: void
12      */
13     public void update(String content);
14 }
观察者接口
 1 /**
 2  * 目标对象,它知道观察它的观察者,并提供注册(添加)和删除观察者的接口。
 3  * @author Administrator
 4  *
 5  */
 6 public class WeatherSubject {
 7     // 用来保存注册的观察者对象
 8     List<Observer> observers = new ArrayList<Observer>();
 9 
10     /**
11      * 把订阅的人添加到订阅者列表中
12      */
13     public void attach(Observer observer) {
14         observers.add(observer);
15     }
16 
17     /**
18      * 从集合中删除观察者
19      */
20     public void detach(Observer observer) {
21         if (observers.contains(observer)) {
22             observers.remove(observer);
23         }
24     }
25 
26     /**
27      * 通知所有注册的观察者对象
28      */
29     protected void notifyObservers(String content) {
30         for (Observer observer : observers) {
31             observer.update(content);
32         }
33     }
34 }
目标对象

  2.分别创建具体的目标对象和具体的观察者对象

  

 1 /**
 2  * 具体的目标对象,负责把有关状态存入到相应的观察者对象中
 3  * @author Administrator
 4  *
 5  */
 6 public class ConcreteWeatherSubject extends WeatherSubject {
 7     //获取天气的内容信息
 8     private String weatherContent;
 9 
10     /**
11      * @return the weatherContent
12      */
13     public String getWeatherContent() {
14         return weatherContent;
15     }
16 
17     /**
18      * @param weatherContent the weatherContent to set
19      */
20     public void setWeatherContent(String weatherContent) {
21         this.weatherContent = weatherContent;
22         //内容有了,说明天气更细了,通知所有的订阅人
23         this.notifyObservers(weatherContent);
24     }
25     
26 }
具体目标对象
 1 /**
 2  * 具体的观察者对象,实现更新的方法,使自身的状态和目标的状态保持一致
 3  * @author Administrator
 4  *
 5  */
 6 public class ConcreteObserver implements Observer {
 7     //观察者的名字,是谁收到了这个信息
 8     private String observerName;
 9     
10     //天气内容的情况,这个消息从目标处获取
11     private String weatherContent;
12     
13     //提醒的内容,根据不同的人提醒不同的信息
14     private String remindThing;
15     
16     /**
17      * 获取目标类的状态同步到观察者的状态中
18      */
19     @Override
20     public void update(String content) {
21         weatherContent = content;
22         System.out.println(observerName+"收到了"+weatherContent+","+remindThing);
23     }
24 
25     /**
26      * @return the observerName
27      */
28     public String getObserverName() {
29         return observerName;
30     }
31 
32     /**
33      * @param observerName the observerName to set
34      */
35     public void setObserverName(String observerName) {
36         this.observerName = observerName;
37     }
38 
39     /**
40      * @return the weatherContent
41      */
42     public String getWeatherContent() {
43         return weatherContent;
44     }
45 
46     /**
47      * @param weatherContent the weatherContent to set
48      */
49     public void setWeatherContent(String weatherContent) {
50         this.weatherContent = weatherContent;
51     }
52 
53     /**
54      * @return the remindThing
55      */
56     public String getRemindThing() {
57         return remindThing;
58     }
59 
60     /**
61      * @param remindThing the remindThing to set
62      */
63     public void setRemindThing(String remindThing) {
64         this.remindThing = remindThing;
65     }
66     
67 }
具体观察者对象

  3.创建测试类进行测试

 1 public class Test {
 2     public static void main(String[] args) {
 3         // 1.创建一个目标
 4         ConcreteWeatherSubject subject = new ConcreteWeatherSubject();
 5 
 6         // 2.创建一个观察者
 7         ConcreteObserver girlObserver = new ConcreteObserver();
 8         girlObserver.setObserverName("黄明的女朋友");
 9         girlObserver.setRemindThing("天气很好,适合约会");
10 
11         ConcreteObserver mumObserver = new ConcreteObserver();
12         mumObserver.setObserverName("黄明的老妈");
13         mumObserver.setRemindThing("天气很好,适合购物");
14 
15         // 3.注册观察者
16         subject.attach(girlObserver);
17         ;
18         subject.attach(mumObserver);
19 
20         // 4.目标发布天气
21         subject.setWeatherContent("明天天气晴朗,气温28度");
22     }
23 }
测试类

使用Java提供的观察者实现进行实例测试:

  1.创建目标的具体实现类,继承于Java提供的Observable类

 1 /**
 2  * 天气目标的具体实现类
 3  * @author Administrator
 4  *
 5  */
 6 public class ConcreteWeatherSubject extends Observable {
 7     //天气情况的内容
 8     private String content;
 9 
10     public String getContent() {
11         return content;
12     }
13     
14     public void setContent(String content) {
15         this.content = content;
16         //天气情况有了,就要通知所有的观察者
17         //注意在通知之前,在用Java中的Observer模式的时候,下面这句话不可少
18         this.setChanged();
19         //然后主动通知,这里用推的模式实现
20         this.notifyObservers(content);
21         //如果是拉的模式实现,使用不带参数的
22         //this.notifyObservers();
23     }
24     
25 }
具体目标类

  2.创建具体的观察者对象,实现Java提供的Observer接口

 1 /**
 2  * 具体的观察者对象
 3  * @author Administrator
 4  *
 5  */
 6 public class ConcreteObserver implements Observer {
 7 
 8     //观察者名称的变量
 9     private String observerName;
10     @Override
11     public void update(Observable o, Object arg) {
12         //第一种是推的方式
13         System.out.println(observerName+"收到了消息,目标推送过来的是:"+arg);
14         //第二种是拉的方式
15         System.out.println(observerName+"收到了消息,主动到目标对象中去拉,拉的内容是"
16                 +((ConcreteWeatherSubject)o).getContent());
17     }
18     public String getObserverName() {
19         return observerName;
20     }
21     public void setObserverName(String observerName) {
22         this.observerName = observerName;
23     }
24     
25 }
观察者的具体实现

  3.测试类

 1 /**
 2  * 测试类
 3  * @author Administrator
 4  *
 5  */
 6 public class Test {
 7     public static void main(String[] args) {
 8         //创建天气作为一个目标,也可以说是被观察者
 9         ConcreteWeatherSubject subject = new ConcreteWeatherSubject();
10         //创建黄明的女朋友作为观察者
11         ConcreteObserver girlObserver = new ConcreteObserver();
12         girlObserver.setObserverName("黄明的女朋友");
13         //创建黄明的老妈作为观察者
14         ConcreteObserver mumObserver = new ConcreteObserver();
15         mumObserver.setObserverName("黄明的老妈");
16         
17         //注册观察者
18         subject.addObserver(mumObserver);
19         subject.addObserver(girlObserver);
20         
21         //目标更新天气情况
22         subject.setContent("天气晴,气温28度");
23     }
24 }
测试类

猜你喜欢

转载自www.cnblogs.com/wk-missQ1/p/12319432.html