码迷,mamicode.com
首页 > 其他好文 > 详细

设计模式--观察者模式

时间:2017-03-30 18:37:42      阅读:198      评论:0      收藏:0      [点我收藏+]

标签:point   接受   消息队列   exception   朝鲜   string   opera   rgs   发布   

设计模式--观察者模式

1 概述


1.1 定义
观察者模式(Observer Design),也叫发布订阅模式:定义对象间一对多的依赖关系,使得每当一个对象状态改变时,它的所有依赖者都会收到通知并自动更新。

1.2 应用
消息队列的处理机制,如EJB的消息队列。(原理基本相同)

1.3 类图
技术分享

组合模式涉及的角色如下:

  • Subject被观察者抽象角色:定义被观察者需要实现的行为,如动态的添加、删除观察者、通知观察者。
  • ConcreteSubject被观察者具体角色:被观察者抽象角色的具体实现,定义自己的业务逻辑,并通知观察者。
  • Observer观察者抽象角色:定义观察者的抽象行为。
  • ConcteteObserver观察者具体角色:具体的观察者,实现自己的业务逻辑。

2 详解

 1 public interface Observer {
 2     void update(Object arg);
 3 }
 4 
 5 public class ConcreteObserver implements Observer {
 6     @Override
 7     public void update(Object arg) {
 8         System.out.println("I accept arg: " + arg);
 9     }
10 }
11 
12 public abstract class Subject {
13     // 定义一个观察者数组(Vector线程安全)
14     private Vector<Observer> vector = new Vector<>();
15 
16     // 添加观察者
17     public synchronized void addObserver(Observer observer) {
18         vector.addElement(observer);
19     }
20 
21     // 删除一个观察者
22     public synchronized void removeObserver(Observer observer) {
23         vector.removeElement(observer);
24     }
25 
26     // 清空观察者
27     public synchronized void clear(Observer observer) {
28         vector.removeAllElements();
29     }
30 
31     // 通知观察者
32     public synchronized void notifyObservers(Object arg) {
33         for(Observer observer : vector) {
34             observer.update(arg);
35         }
36     }
37 }
38 
39 public class ConcreteSubject extends Subject {
40     // 定义自己的业务逻辑并通知观察者
41     public void operate() {
42         System.out.println("I do some operations and notify observes");
43         notifyObservers(null);
44     }
45 }
46 
47 public class Client {
48     public static void main(String[] args) {
49         // 创建观察者
50         Observer observer = new ConcreteObserver();
51         Observer observer1 = new ConcreteObserver();
52 
53         // 创建被观察者并添加观察者
54         ConcreteSubject subject = new ConcreteSubject();
55         subject.addObserver(observer);
56         subject.addObserver(observer1);
57 
58         // 被观察者活动并通知观察者
59         subject.operate();
60     }
61 }output:
62 I do some operations and notify observes
63 I accept arg: null
64 I accept arg: null

JDK中自带了有观察者模式:java.util.Observable是被观察者抽象角色,java.util.Observer是观察者抽象角色。你只需要实现自己的观察者与被观察者就可使用。

 1 public interface Observer {
 2     void update(Observable o, Object arg);
 3 }
 4 
 5 public class Observable {
 6     // 标识:标识被观察者是否改变
 7     private boolean changed = false;
 8     private Vector<Observer> obs;
 9 
10     public Observable() {
11         obs = new Vector<>();
12     }
13     // 添加观察者
14     public synchronized void addObserver(Observer o) {
15         if (o == null)
16             throw new NullPointerException();
17         if (!obs.contains(o)) {
18             obs.addElement(o);
19         }
20     }
21     // 删除观察者
22     public synchronized void deleteObserver(Observer o) {
23         obs.removeElement(o);
24     }
25     // 清空观察者
26     public synchronized void deleteObservers() {
27         obs.removeAllElements();
28     }
29     // 通知所有观察者
30     public void notifyObservers() {
31         notifyObservers(null);
32     }
33     public void notifyObservers(Object arg) {
34         /**
35          * 一个观察者缓冲区,用于并发访问被观察者时,留住观察者列表的当前状态,这样能够减少该对象加锁的时
36          * 间,这种处理方式其实也算是一种设计模式,即备忘录模式。
37          */
38         Object[] arrLocal;
39     /**
40      * 同步块:获得所有的观察者,以通知所有的观察者。这里使用同步块能够避免在通知中有人修改观察者
41      * 集合。如上所诉,使用观察者缓冲区能够减少该对象的加锁时间。
42      */
43         synchronized (this) {
44             if (!changed)
45                 return;
46             arrLocal = obs.toArray();
47             clearChanged();
48         }
49 
50         for (int i = arrLocal.length-1; i>=0; i--)
51             ((Observer)arrLocal[i]).update(this, arg);
52     }
53     // 设置该被观察者改变标识为true
54     protected synchronized void setChanged() {
55         changed = true;
56     }
57     // 设置该被观察者改变标识为false
58     protected synchronized void clearChanged() {
59         changed = false;
60     }
61 
62     public synchronized boolean hasChanged() {
63         return changed;
64     }
65     
66     public synchronized int countObservers() {
67         return obs.size();
68     }

小结一下

  1. 观察者模式就是使用的回调机制,它更注重发布-订阅。被观察者一般有许多的观察者,被观察者会通知所有的观察者。在现实生活中就像微信工作号一样,只要你关注了它,它就会给你推送消息。
  2. JDK中的观察者能够是线程安全的。但是当我们观察者处理通知时间较长时,会发生阻塞,因为其通知观察者是采用了同步的方式,而不是异步方式。
  3. 不足:观察者模式中被观察者是一个抽象类,只能单继承,当然可以使用设配器模式。观察者模式中的观察者响应是固定的,即update()方法。

3 应用

技术分享
 1 public class People implements Observer {
 2     private WeChat weChat;
 3     private String name;
 4 
 5     People(String name, WeChat weChat) {
 6         this.name = name;
 7         this.weChat = weChat;
 8     }
 9 
10     // 订阅微信公众号
11     public boolean order (String name) {
12         return weChat.order(this, name);
13     }
14 
15     // 接受微信公众号发送的消息
16     public void recieveMessage(Observable o, Object arg) {
17         System.out.println(name + "接收到微信公众号「" + o + "」的信息:" + arg);
18     }
19 
20     @Override
21     public void update(Observable o, Object arg) {
22         recieveMessage(o, arg);
23     }
24 }
25 
26 /**
27  * 微信公众号
28  */
29 public class WeChatPublicMessage extends Observable {
30     private String name;
31 
32     WeChatPublicMessage(String name) {
33         super();
34         this.name = name;
35     }
36 
37     // 发布消息
38     public void publish(String message) {
39         setChanged();
40         notifyObservers(message);
41     }
42     
43     @Override
44     public String toString() {
45         return name;
46     }
47 
48 }
49 
50 public class WeChat {
51     public static HashMap<String, WeChatPublicMessage> map = new HashMap<>();
52 
53     // 订阅微信公众号
54     public boolean order(People people, String name) {
55         WeChatPublicMessage weChatPublicMessage = map.get(name);
56         if(weChatPublicMessage == null) {
57             return false;
58         }
59         // 该微信公众号添加订阅人
60         weChatPublicMessage.addObserver(people);
61         return true;
62     }
63 }
64 
65 public class Client {
66     public static void main(String[] args) {
67         WeChatPublicMessage weChatPublicMessage = new WeChatPublicMessage("小道消息");
68         WeChatPublicMessage weChatPublicMessage1 = new WeChatPublicMessage("侠客岛");
69         WeChatPublicMessage weChatPublicMessage2 = new WeChatPublicMessage("财新网");
70         WeChat.map.put("小道消息", weChatPublicMessage);
71         WeChat.map.put("侠客岛", weChatPublicMessage1);
72         WeChat.map.put("财新网", weChatPublicMessage2);
73 
74         People people = new People("张三", new WeChat());
75         People people1 = new People("李四", new WeChat());
76 
77         people.order("小道消息");
78         people.order("财新网");
79         people.order("侠客岛");
80         people1.order("财新网");
81 
82         weChatPublicMessage.publish("今天三星S8发布");
83         weChatPublicMessage1.publish("韩美举行大规模的军演,朝鲜发出严正抗议");
84         weChatPublicMessage2.publish("第一季度中国GDP同比增长6.6%");
85     }
86 }output:
87 张三接收到微信公众号「小道消息」的信息:今天三星S8发布
88 张三接收到微信公众号「侠客岛」的信息:韩美举行大规模的军演,朝鲜发出严正抗议
89 李四接收到微信公众号「财新网」的信息:第一季度中国GDP同比增长6.6%
90 张三接收到微信公众号「财新网」的信息:第一季度中国GDP同比增长6.6%
View Code

设计模式--观察者模式

标签:point   接受   消息队列   exception   朝鲜   string   opera   rgs   发布   

原文地址:http://www.cnblogs.com/maying3010/p/6647583.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!