设计模式--观察者模式
Posted 默默的看雨下
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式--观察者模式相关的知识,希望对你有一定的参考价值。
设计模式--观察者模式
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 }
小结一下
- 观察者模式就是使用的回调机制,它更注重发布-订阅。被观察者一般有许多的观察者,被观察者会通知所有的观察者。在现实生活中就像微信工作号一样,只要你关注了它,它就会给你推送消息。
- JDK中的观察者能够是线程安全的。但是当我们观察者处理通知时间较长时,会发生阻塞,因为其通知观察者是采用了同步的方式,而不是异步方式。
- 不足:观察者模式中被观察者是一个抽象类,只能单继承,当然可以使用设配器模式。观察者模式中的观察者响应是固定的,即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%
以上是关于设计模式--观察者模式的主要内容,如果未能解决你的问题,请参考以下文章
Java设计模式补充:回调模式事件监听器模式观察者模式(转)