• 观察者模式介绍

  观察者模式是一种非常有用的设计模式,在软件系统中,当一个对象的行为依赖于另一个对象的状态时,观察者模式就非常有用。如果不适用观察者模式,而实现类似的功能,可能就需要另外启动一个线程不停地监听另一个对象的状态,这样会得不偿失。如果在一个复杂的系统中,可能就需要开启很多的线程来监听对象状态的变化,这样会使系统的性能产生额外的负担。而观察者模式就可以在单线程下使某一对象及时得知所依赖对象状态的变化而做出行为。

  观察者模式的经典结构:

  

  其中ISubject是观察对象(被观察者对象),它维持着一个观察者对象列表,可以增加或删除观察者。IObserver是观察者,它依赖于ISubject对象状态的变化而做出行为。当ISubject对象的状态发生变化时,它可以通过inform()方法通知观察者。

  观察者模式的主要角色功能如下图:

  

  • 观察者实例

  现在简单实现一个观察者的小例子。

  主题接口:

 public interface ISubject {
void attach(IObserver observer);
void detach(IObserver observer);
void inform();
}

  观察者接口:

 public interface IObserver {
void update(Event event);
}

  事件(对应现实中的点击等事件也可以理解为上文中说到的状态变化):

 public class Event {

 }

  具体的主题实现:

 public class ConcreteSubject implements ISubject {
Vector<IObserver> obversers = new Vector<IObserver>();//观察者队列
@Override
public void attach(IObserver observer) {
obversers.add(observer);
} @Override
public void detach(IObserver observer) {
obversers.remove(observer);
} @Override
public void inform() {
Event event = new Event();
for(IObserver obverser:obversers){
obverser.update(event);
}
} }

  具体的观察者:

 public class ConcreteObserver implements IObserver {

     @Override
public void update(Event event) {
System.out.println("ConcreteObserver.update()");
} }

  测试代码:

public class Test {
public static void main(String[] args) {
IObserver observer1 = new ConcreteObserver();
IObserver observer2 = new ConcreteObserver();
ISubject subject = new ConcreteSubject();
subject.attach(observer1);
subject.attach(observer2);
subject.inform();
}
}

  可以看出,通过被观察者状态变化而调用某一方法使观察者收到通知而做出反应,通过委托降低了代码的耦合度。

  观察者模式十分常用,以致于JDK内部就为开发人员准备了一套观察者模式的实现。在java.util包中,就包括了Obserable类和Observer接口。在Observable中就实现了观察对象的主要功能,如:添加观察者、删除观察者和通知观察者等。Observer是观察者接口,它的update方法会在Obserable类的notifyObservers()中被回调以获得最新的状态变化。

  以现在比较火热的购房作为观察者模式的一个例子:现在很多购房者关注房价的变化,每当房价发生变动的时候,购房者就会收到通知。这样购房者就是观察者,他们关注着房子的价格。

  观察对象房子代码:

 public class House extends Observable{
private float price; public House(float price) {
super();
this.price = price;
} public float getPrice() {
return price;
} public void setPrice(float price) {
super.setChanged();//设置变化点
super.notifyObservers(price);//价格变动
this.price = price;
} @Override
public String toString() {
// TODO Auto-generated method stub
return "房子的价格为:"+this.price;
}
}

  观察者购房者代码:

 public class CustomerObserver implements Observer{

     private String name;

     public CustomerObserver(String name) {
super();
this.name = name;
} @Override
public void update(Observable o, Object arg) {
if (arg instanceof Float) {
System.out.println(this.name+"观察到房子价格变动为:"+arg);
}
}
}

  测试代码:

 public class Test1 {
public static void main(String[] args) {
House h = new House(1000000) ;
CustomerObserver hpo1 = new CustomerObserver("购房者A") ;
CustomerObserver hpo2 = new CustomerObserver("购房者B") ;
CustomerObserver hpo3 = new CustomerObserver("购房者C") ;
h.addObserver(hpo1) ;
h.addObserver(hpo2) ;
h.addObserver(hpo3) ;
System.out.println(h) ; // 输出房子价格
h.setPrice(666666) ; // 修改房子价格
System.out.println(h) ; // 输出房子价格
}
}

  输出结果为:

 房子价格为:1000000.0
购房者C观察到价格更改为:666666.0
购房者B观察到价格更改为:666666.0
购房者A观察到价格更改为:666666.0
房子价格为:666666.0

  Observer源码:

 public class Observable {
private boolean changed = false;//判断观察对象是否发生变化
private Vector obs;//观察者队列
public Observable() {
obs = new Vector();
} public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
} public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
} public void notifyObservers() {
notifyObservers(null);
} //通知观察者
public void notifyObservers(Object arg) { Object[] arrLocal; synchronized (this) { if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
} for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
} public synchronized void deleteObservers() {
obs.removeAllElements();
} protected synchronized void setChanged() {
changed = true;
} protected synchronized void clearChanged() {
changed = false;
} public synchronized boolean hasChanged() {
return changed;
} public synchronized int countObservers() {
return obs.size();
}
}

  可以发现JDK中实现的观察者模式,用法简单功能强大,和我们上面写的观察者模式实现原理是一样的。观察者模式可以用于事件监听、通知发布等场合,可以确保观察者在不适用轮询监控的情况下,可以及时得到相关消息和事件。

java设计优化--观察者模式的更多相关文章

  1. java设计优化--代理模式

    代理模式使用代理对象完成用户的请求,屏蔽用户对真实对象的访问. 代理模式的用途很多,比如因为安全原因,需要屏蔽客户端直接访问真实对象:或者在远程调用中,需要使用代理对象处理远程方法中的技术细节:或者为 ...

  2. java设计优化--单例模式

    单例模式是一种对象创建模式,确保系统中一个类只有一个实例. 在java语言中,这样做有两大好处: 1.对于频繁使用的对象,可以省略创建对象所话费的时间: 2.由于new操作的次数减少,对于系统内存的使 ...

  3. java设计优化--装饰者模式

    装饰者模式拥有一个设计非常巧妙的结构,它可以动态的添加功能.在基本的设计原则中,有一条重要的设计准则就是合成/聚合复用原则.根据该原则的思想,代码复用应该尽可能使用委托,而不是使用继承.因为继承是一种 ...

  4. java设计优化-享元模式

    享元模式是设计模式中少数几个以调高系统性能为目的的设计模式.它的核心思想是:如果在一个系统中存在多个相同的对象,那么只需共享一份对象的拷贝,而不必为每一次使用都创建新的对象.在享元模式中,由于需要构建 ...

  5. 《Java程序性能优化》学习笔记 设计优化

    豆瓣读书:http://book.douban.com/subject/19969386/ 第一章 Java性能调优概述 1.性能的参考指标 执行时间: CPU时间: 内存分配: 磁盘吞吐量: 网络吞 ...

  6. 《Java程序性能优化》之设计优化

    豆瓣读书:http://book.douban.com/subject/19969386/ 第一章 Java性能调优概述 1.性能的参考指标 执行时间: CPU时间: 内存分配: 磁盘吞吐量: 网络吞 ...

  7. Java 程序优化 (读书笔记)

    --From : JAVA程序性能优化 (葛一鸣,清华大学出版社,2012/10第一版) 1. java性能调优概述 1.1 性能概述 程序性能: 执行速度,内存分配,启动时间, 负载承受能力. 性能 ...

  8. 从设计模式的角度看Java程序优化

    一.前言 Java程序优化有很多种渠道,比如jvm优化.数据库优化等等,但都是亡羊补牢的措施,如果能在设计程序架构时利用设计模式就把程序的短板解决,就能使程序更加健壮切容易维护迭代 二.常用的设计模式 ...

  9. JAVA性能优化的五种方式

    一,JAVA性能优化之设计优化 设计优化处于性能优化手段的上层.它往往须要在软件开发之前进行.在软件开发之前,系统架构师应该就评估系统可能存在的各种潜在问题和技术难点,并给出合理的设计方案,因为软件设 ...

随机推荐

  1. Hadoop 2.0中单点故障解决方案总结

    Hadoop 1.0内核主要由两个分支组成:MapReduce和HDFS,众所周知,这两个系统的设计缺陷是单点故障,即MR的JobTracker和HDFS的NameNode两个核心服务均存在单点问题, ...

  2. POJ 3255 Roadblocks --次短路径

    由于次短路一定存在,则可知次短路一定是最短路中某一条边不走,然后回到最短路,而且只是一条边,两条边以上不走的话,就一定不会是次短路了(即以边换边才能使最小).所以可以枚举每一条边,算出从起点到这条边起 ...

  3. Redis 一二事 - 在spring中使用jedis 连接调试单机redis以及集群redis

    Redis真是好,其中的键值用起来真心强大啊有木有, 之前的文章讲过搭建了redis集群 那么咋们该如何调用单机版的redis以及集群版的redis来使用缓存服务呢? 先讲讲单机版的,单机版redis ...

  4. QTP基础学习(一)安装目录介绍

    上一篇介绍了QTP 10 安装,安装完成后就可以看到文件的目录了,这里主要介绍以下几个目录及作用. 简单介绍部分目录 1.addins:插件包 2.bin目录:可执行程序,这里存储了很多配置文件.运行 ...

  5. javascript js string.Format()收集

    方案1http://www.cnblogs.com/loogn/archive/2011/06/20/2085165.html String.prototype.format = function(a ...

  6. android获取当前行所属类和所属方法名

        第一种方法: String Method = Thread.currentThread().getStackTrace()[2].getMethodName();   第二种方法: priva ...

  7. SQL 时间处理

    1.获取当前时间 GetDate() 2.获取当前年.月.日 DATEPART(yyyy,GetDate()).DATEPART(m,GetDate()).DATEPART(d,GetDate()) ...

  8. 【转】【C#】C#重绘windows窗体标题栏和边框

    摘要 windows桌面应用程序都有标准的标题栏和边框,大部分程序也默认使用这些样式,一些对视觉效果要求较高的程序,如QQ, MSN,迅雷等聊天工具的样式则与传统的windows程序大不相同,其中迅雷 ...

  9. immutability-javascript

    https://www.sitepoint.com/immutability-javascript/

  10. web前端性能意义、关注重点、测试方案、优化技巧

    1.前段性能的意义 对于访问一个网站,最花费时间的并不是后端应用程序处理以及数据库等消耗的时间,而是前端花费的时间(包括请求.网络传输.页面加载.渲染等).根据web优化的黄金法则: 80%的最终用户 ...