java设计模式-观察者模式
2016-08-10 23:26
453 查看
定义:
使用head First 设计模式中提到的说法
观察者模式定义了一个一对多的依赖关系,让一个或多个观察者对象监听一个主题对象。这样一来,当被观察者状态发生改变时,需要通知相应的观察者,使这些观察者对象能够自动更新。简介:
观察者模式(Observer)完美的将观察者和被观察的对象分离开。举个例子,用户界面可以作为一个观察者,业务数据是被观察者,用户界面观察业务数据的变化,发现数据变化后,就显示在界面上。面向对象设计的一个原则是:
系统中的每个类将重点放在某一个功能上,而不是其他方面。一个对象只做一件事情,并且将他做好。观察者模式在模块之间划定了清晰的界限,提高了应用程序的可维护性和重用性。观察者设计模式定义了对象间的一种一对多的依赖关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动刷新。
实现方式
实现观察者模式的时候要注意,观察者和被观察对象之间的互动关系不能体现成类之间的直接调用,否则就将使观察者和被观察对象之间紧密的耦合起来,从根本上违反面向对象的设计的原则。无论是观察者“观察”观察对象,还是被观察者将自己的改变“通知”观察者,都不应该直接调用。组成元素:
主题
主题是观察者观察的对象,一个主题必须具备下面三个特征。
持有监听的观察者的引用支持增加和删除观察者
主题状态改变,通知观察者
观察者
当主题发生变化,收到通知进行具体的处理是观察者必须具备的特征。1.自定义实现例子:
代码:(使用了泛型和反射)
//观察者,需要用到观察者模式的类需实现此接口 public interface Observer{ void update(Object...objs); } //被观察者(一个抽象类,方便扩展) public abstract class Observable{ public final ArrayList<Class<?>> obserList = new ArrayList<Class<?>>(); /**AttachObserver(通过实例注册观察者) *<b>Notice:</b>obcan'tbenull,oritwillthrowNullPointerException **/ public<T> void registerObserver(T ob){ if(ob==null) throw new NullPointerException(); this.registerObserver(ob.getClass()); } /** *AttachObserver(通过Class注册观察者) *@paramcls */ public void registerObserver(Class<?> cls){ if(cls==null) throw new NullPointerException(); synchronized(obserList){ if(!obserList.contains(cls)){ obserList.add(cls); } } } /**UnattachObserver(注销观察者) *<b>Notice:</b> *<b>ItreverseswithattachObserver()method</b> **/ public<T>void unRegisterObserver(Tob){ if(ob==null) throw new NullPointerException(); this.unRegisterObserver(ob.getClass()); } /**UnattachObserver(注销观察者,有时候在未获取到实例使用) *<b>Notice:</b> *<b>ItreverseswithattachObserver()method</b> **/ public void unRegisterObserver(Class<?>cls){ if(cls==null) throw new NullPointerException(); synchronized(obserList){ Iterator<Class<?>>iterator=obserList.iterator(); while(iterator.hasNext()){ if(iterator.next().getName().equals(cls.getName())){ iterator.remove(); break; } } } } /**detachallobservers*/ public void unRegisterAll(){ synchronized(obserList){ obserList.clear(); } } /**Ruturnthesizeofobservers*/ public int countObservers(){ synchronized(obserList){ returnobserList.size(); } } /** *notify all observer(通知所有观察者,在子类中实现) *@paramobjs */ public abstract void notifyObservers(Object... objs); /** *notify one certain observer(通知某一个确定的观察者) *@paramcls *@paramobjs */ public abstract void notifyObserver(Class<?> cls, Object... objs); /** *notifyonecertainobserver *@paramcls *@paramobjs */ public abstract<T> void notifyObserver(T t, Object... objs); } //目标被观察者 public class ConcreteObservable extends Observable{ private static ConcreteObservableinstance = null; private ConcreteObservable(){}; public static synchronized ConcreteObservablegetInstance(){ if(instance == null){ instance=newConcreteObservable(); } returninstance; } @Override public <T> void notifyObserver(T t, Object... objs){ if(t == null) throw new NullPointerException(); this.notifyObserver(t.getClass(), objs); } @Override public void notifyObservers(Object... objs){ for(Class<?>cls : obserList){ this.notifyObserver(cls, objs); } } //通过java反射机制实现调用 @Override public void notifyObserver(Class<?>cls, Object...objs){ if(cls == null) throw new NullPointerException(); Method[] methods = cls.getDeclaredMethods(); for(Method method : methods){ if(method.getName().equals("update")){ try{ method.invoke(cls,objs); break; }catch(IllegalArgumentException e){ e.printStackTrace(); }catch(IllegalAccessException e){ e.printStackTrace(); }catch(InvocationTargetException e){ e.printStackTrace(); } } } } } //使用(实现Observer接口) public class Text extends Activity implements Observer{ publicvoidonCreate(...){ ConcreteObservable.getInstance().registerObserver(Text.class); .... } //实现接口处理 publicvoidupdate(Object...objs){ //做操作,比如更新数据,更新UI等 } }
2.java内置的实现方式:
java.util.Observable 这是一个类,而非接口,主题需要继承这个类。java.util.Observer 这是一个接口,监听者需要实现这个接口。
代码:
import java.util.Observable; import java.util.Observer; public class MainRoot { public static void main(String[] args) { Observer consumer = new Consumer(); MilkProvider provider = new MilkProvider(); provider.addObserver(consumer); provider.milkProduced(); } static class MilkProvider extends Observable { public void milkProduced() { setChanged();//状态改变,必须调用 notifyObservers(); } } static class Consumer implements Observer { @Override public void update(Observable arg0, Object arg1) { System.out.println("Consumer update..." + arg0 + ";arg1=" + arg1); } } }
setChange讲解
源代码:protected synchronized void setChanged() { changed = true; }
setChange的意义:
1.筛选有效通知,只有有效通知可以调用setChanged。比如,我的微信朋友圈一条状态,好友A点赞,后续该状态的点赞和评论并不是每条都通知A,只有A的好友触发的操作才会通知A。2.便于撤销通知操作,在主题中,我们可以设置很多次setChanged,但是在最后由于某种原因需要取消通知,我们可以使用clearChanged轻松解决问题。
3.主动权控制,由于setChanged为protected,而notifyObservers方法为public,这就导致存在外部随意调用notifyObservers的可能,但是外部无法调用setChanged,因此真正的控制权应该在主题这里。
如何主动获取通知:
需要主题为某些数据提供getter方法,观察者只需调用getter取数据处理即可。
代码:
static class MilkProvider extends Observable { public void milkProduced() { setChanged();//状态改变,必须调用 notifyObservers(); } public float getPrice() { return 2.5f; } } static class Consumer implements Observer { @Override public void update(Observable arg0, Object arg1) { MilkProvider provider = (MilkProvider)arg0; System.out.println("milk price =" + provider.getPrice()); } }
观察者模式的优点:
1.观察者增加或删除无需修改主题的代码,只需调用主题对应的增加或者删除的方法即可。2.主题只负责通知观察者,但无需了解观察者如何处理通知。
3.观察者只需等待主题通知,无需观察主题相关的细节。
4.由于被动接受,正常情况下不会错过主题的改变通知。而主动获取的话,由于时机选取问题,可能导致错过某些状态。
缺点:
1.主题持有观察者的引用,如果未正常处理从主题中删除观察者,会导致观察者无法被回收。2.如果观察者具体实现代码有问题,会导致主题和观察者对象形成循环引用,在某些采用引用计数的垃圾回收器可能导致无法回收。
我的微信二维码如下,欢迎交流讨论
欢迎关注《IT面试题汇总》微信订阅号。每天推送经典面试题和面试心得技巧,都是干货!
微信订阅号二维码如下:
参考:
http://baike.baidu.com/view/1854779.htm
http://droidyue.com/blog/2015/06/27/desgign-pattern-observer/index.html
<script type="text/javascript">
$(function () {
$('pre.prettyprint code').each(function () {
var lines = $(this).text().split('\n').length;
var $numbering = $('<ul/>').addClass('pre-numbering').hide();
$(this).addClass('has-numbering').parent().append($numbering);
for (i = 1; i <= lines; i++) {
$numbering.append($('<li/>').text(i));
};
$numbering.fadeIn(1700);
});
});
</script>
相关文章推荐
- Java环境变量的具体配置
- 编码练习——Java-1-基础
- leetcode算法——258:Add Digits(基于JAVA)
- 欢迎使用CSDN-markdown编辑器
- springAOP
- Eclipse安装git
- Java HashMap工作原理及实现?
- zz Java语法糖之泛型 - 综述
- MyEclipse2014的妙用-增加注释模板
- java类里的成员变量是自身的对象问题
- java中关于String类型和double,int类型之间的转换
- Kafka学习笔记-Java简单操作
- Java基础知识
- 安装java之后,找不到tools.jar 和dt.jar
- Java中String与基本数据类型间的转换
- Java多线程六:生产者和消费者模型(多对多)
- Java编程知识点——Scanner
- 6-1、java.util.LinkedList
- 生产者与消费者小例子
- Spring Boot 配置优先级顺序