java设计模式之观察者模式
2016-01-25 21:56
561 查看
1、概述:
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,当这个主题在状态发生变化的时候,会通知所有观察者对象,使他们能够更新自己。
2、解决的问题:
将一个系统分割成一个一些类相互协作的类有一个不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便。观察者就是解决这类的耦合关系的。
3、模式中的角色
3.1 抽象主题(Subject):它把所有观察者对象的引用保存到一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
3.2 具体主题(ConcreteSubject):将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。
3.3 抽象观察者(Observer):为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
3.4 具体观察者(ConcreteObserver):实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态协调。
4、类图
5. 模式总结
5.1 优点
5.1.1 观察者模式解除了主题和具体观察者的耦合,让耦合的双方都依赖于抽象,而不是依赖具体。从而使得各自的变化都不会影响另一边的变化。
5.2 缺点
5.2.1 依赖关系并未完全解除,抽象通知者依旧依赖抽象的观察者。
5.3 适用场景
5.3.1 当一个对象的改变需要给变其它对象时,而且它不知道具体有多少个对象有待改变时。
5.3.2 一个抽象某型有两个方面,当其中一个方面依赖于另一个方面,这时用观察者模式可以将这两者封装在独立的对象中使它们各自独立地改变和复用。
6、java代码实现
主题抽象类:
client端代码:
测试结果:
7、注意事项:
7.1抽象观察者一般用接口实现,因为监听的类你不知道它是什么类型,不知道这个类是不是已经继承过其他父类,所以用接口实现更好。
7.2代码中我把Observer都改成了Listener,因为觉得方法名attach、dettach都不太容易让人理解是什么意思,改成addListener,deleteLinstener更容易理解,举例一个输入框分别有两类监听者,单击有一群监听者,双击也有一群监听者,名字就可以改成addClickListener、addDoubleClickListener,比attach容易扩展。
7.3通知各个监听者的时候用线程更好,因为如果其中一个观察者的update异常了或者执行时间太长, 就会影响到其他观察者的update方法,用线程就避免了这个问题。
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,当这个主题在状态发生变化的时候,会通知所有观察者对象,使他们能够更新自己。
2、解决的问题:
将一个系统分割成一个一些类相互协作的类有一个不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便。观察者就是解决这类的耦合关系的。
3、模式中的角色
3.1 抽象主题(Subject):它把所有观察者对象的引用保存到一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
3.2 具体主题(ConcreteSubject):将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。
3.3 抽象观察者(Observer):为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
3.4 具体观察者(ConcreteObserver):实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态协调。
4、类图
5. 模式总结
5.1 优点
5.1.1 观察者模式解除了主题和具体观察者的耦合,让耦合的双方都依赖于抽象,而不是依赖具体。从而使得各自的变化都不会影响另一边的变化。
5.2 缺点
5.2.1 依赖关系并未完全解除,抽象通知者依旧依赖抽象的观察者。
5.3 适用场景
5.3.1 当一个对象的改变需要给变其它对象时,而且它不知道具体有多少个对象有待改变时。
5.3.2 一个抽象某型有两个方面,当其中一个方面依赖于另一个方面,这时用观察者模式可以将这两者封装在独立的对象中使它们各自独立地改变和复用。
6、java代码实现
主题抽象类:
import java.util.ArrayList; import java.util.List; abstract public class Subject { private List<Listener> listenerList=new ArrayList<Listener>(); public void addListener(Listener listener){ for(Listener curlistener:listenerList){ if(curlistener==listener){ return; } } listenerList.add(listener); } public void deleteListener(Listener listener){ // 删除的时候,注意倒序遍历List for(int i=listenerList.size()-1;i>=0;i--){ Listener curlistener=listenerList.get(i); if(curlistener==listener){ listenerList.remove(i); } } } public void notifyAllListeners() { for(final Listener listener:listenerList){ /*此处用线程更好,因为如果其中一个观察者的update异常了或者执行时间太长, 就会影响到其他观察者的update方法,用线程就避免了这个问题。*/ Thread thread=new Thread(new Runnable() { @Override public void run() { listener.update(); } }); thread.start(); } } }
主题实现类: public class Scretary extends Subject { private boolean isback=false; public void changeBossState(){ this.isback=true; System.out.println("老板回来了,大家快注意!"); this.notifyAllListeners(); } }监听者接口类
public interface Listener { public void update(); }监听者实现类
public class ChatListener implements Listener { @Override public void update() { System.out.println("停止聊天,开始工作"); } }
public class StockListener implements Listener { @Override public void update() { System.out.println("关闭股票窗口,开始工作"); } }
client端代码:
public class Client { /** * @param args */ public static void main(String[] args) { Listener stockListener=new StockListener(); Listener chatListener=new ChatListener(); Scretary scretary=new Scretary(); scretary.addListener(stockListener); scretary.addListener(chatListener); scretary.changeBossState(); } }
测试结果:
7、注意事项:
7.1抽象观察者一般用接口实现,因为监听的类你不知道它是什么类型,不知道这个类是不是已经继承过其他父类,所以用接口实现更好。
7.2代码中我把Observer都改成了Listener,因为觉得方法名attach、dettach都不太容易让人理解是什么意思,改成addListener,deleteLinstener更容易理解,举例一个输入框分别有两类监听者,单击有一群监听者,双击也有一群监听者,名字就可以改成addClickListener、addDoubleClickListener,比attach容易扩展。
7.3通知各个监听者的时候用线程更好,因为如果其中一个观察者的update异常了或者执行时间太长, 就会影响到其他观察者的update方法,用线程就避免了这个问题。
相关文章推荐
- 基于websocket的netty框架的理解
- eclipse 中使用git
- Selenium2(java)定位页面元素 二
- The Java™ Tutorials — Generics :Raw Types 原始类型
- Java程序内存分配【一】
- SpringAop编程
- JAVA 笔记 七
- 【慕课笔记】U1 类和对象 第7节 JAVA中的static使用之静态方法
- Spring——jar包详解
- spring面试题
- 【慕课笔记】U1 类和对象 第6节 JAVA中的static使用之静态变量
- 【慕课笔记】U1 类和对象 第5节 JAVA中的构造方法
- Spring notes
- Javaweb自定义标签 tld版本
- Java:杨辉三角
- Java基础之---并发(Concurrency)和多线程
- Spring和springmvc父子容器关系
- myeclipse10 2014(2015),终极破解方案
- Java操作远程共享资源(JCIFS)
- Java web项目的各种路径的获取