java设计模式之观察者模式

来源:互联网 发布:java 流量统计代码 编辑:程序博客网 时间:2024/06/05 16:53

1.观察者适用场景:

     一种事物发生变化时,某些事物会根据该事物的变化做出相应的变化。比如:温度记录仪,当温度发生变化时,需要:1.记录温度日志  2.显示温度变化曲线  3.温度超值时发出警报声。比如:饭熟了,妈妈叫孩子们吃饭,弟弟去摆桌子,姐姐去拿碗筷。察者模式设计到两个因素:主题和观察者。主题是主动的,相当于参照物。比如例子中的温度。观察者,会因主题做出相应改变的事物。比如例子中的温度日志、变化曲线和警报声。第二个例子中,主题是饭,观察者是妈妈、姐姐和弟弟。

2.分析

  首先,主题和观察者是一对多的关系(可以是多对多的关系)。我们可以定义出一种基本的模式:
  while(主题){
     观察者一;
     观察者二;
     观察者三;
  }
        主题要知道有哪些观察者对其监控,所以在主题类中一定有一个集合的成员变量,用来放观察者对象;观察者是多的一方且做出的反应是不同的,所以一定是多态的,可以有共同的父类接口;主题可以对观察者增加、删除和通知。这三个功能是固定的,所以可以从固定的接口派生。


  所以功能类就很明显了:
  主题iSubject接口定义
  主题实现类
  观察者接口iObserver接口定义
  观察者实现类

3.UML类图

  暂略。(感兴趣的可以自己画下)

4.代码实现

//主题接口
package observer;
public interface iSubject {
public void add(iObserver observer2);//添加观察者
public void delete(iObserver observer2);//删除观察者
public void send();//通知观察者
}


//观察者接口
package observer;
public interface iObserver {
  public void refresh(String data);
}


//观察者实现模式
package observer;
public class Observer1 implements iObserver{
@Override
public void refresh(String data) {
       System.out.println("我已经接收到主题的变化数据"+data);
}
}


//主题实现类
package observer;
import java.util.Observer;
import java.util.Vector;
public class Subject implements iSubject{
//存放观察者对象
private Vector<iObserver> vector=new Vector();
//主题数据
private String data;
//get set 方法
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
//添加观察者
@Override
public void add(iObserver observer2) {
        vector.add(observer2);
}
//移除观察者
@Override
public void delete(iObserver observer2) {
vector.remove(observer2);
}
//遍历观察  发通知
@Override
public void send() {
for(int i=0;i<vector.size();i++){
iObserver iob=vector.get(i);
iob.refresh(data);
}
}
}
//测试类
package observer;
public class Test {
public static void main(String[] str) {
Subject subject = new Subject();
iObserver observer = new Observer1();
subject.setData("bb");
subject.add(observer);
subject.send();
}

}


5.观察者模式优化 


  第一个优化点:Subject类中的中心数据是String类型的,iObverser中refersh()方法的参数因此也是String类型的。但是如果是其它类型的,就需要改动代码。我们想到泛型,只要将接口改成泛型接口就可以了。


  第二个优化点:推数据与拉数据。上面Subject类中的数据是直接传递给观察者。从iObserver定义中就能看懂。


//观察者接口
package observer;
public interface iObserver {
  public void refresh(String data);

}


而所谓的拉数据,就是观察者间接获取主题数据,主要是通过获得subject对象,然后访问对象的属性。
  第三个优化点:当需要添加多个类的时候,可以通过实现iSubject中的方法,总体下来会出现很多重复的逻辑代码,比如每个主题实现类都有添加、删除和发通知的代码,只是主题类的中心数据不同而已。可以通过一个中间层的抽象类来实现。
  第四个优化点:避免重复添加同一类型的观察者对象。测试类的部分代码如下:


          Subject subject = new Subject();
subject.setData("我是主题类2的中心数据");

iObserver observer = new Observer1();
iObserver observer2 = new Observer1();
subject.add(observer);
subject.add(observer2);
subject.send();
从代码可以看出,两个观察者对象类型是相同的,都是Observer。但是有些情况下,禁止主题对象添加相同的观察者对象。所以在添加观察者对象之前应该先进行查询,然后判断要不要添加。代码修改如下:
@Override
public void add(iObserver observer2) {
//判断集合中是否已存在该对象
if(!vector.contains(observer2)){
vector.add(observer2);
}
}
注意:Vector类中的conains()方法默认是物理查询,虽然observer,observer2都是Observer类型,但是它们的物理地址是不同的,所以还是会添加同一类型的观察者。解决方法是可以在Observer的具体实现类中重写equals方法,并且增加一个标志。可以在iObserver接口中增加动态方法getMark(),用于获取观察者对象中的MARK值。

六.观察者模式中反射应用

  主要是将观察者类信息封装到XML配置文件中,利用反射技术动态加载观察者信息。配置文件部分内容如下:
  <properties>
    <comment></comment>
    <entry key="observer1">Observer<entry>
   <entry key="observer2">Observer2<entry>
  </properties>
  
注意:
  具体的代码实现参考上传的文件。
  


0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 苹果5s像素不好怎么办 华为mate边缘有缝怎么办 华为mate8边缘有缝怎么办 手机系统占用运行内存大怎么办 安卓手机储存空间不足怎么办 手机显示系统空间不足怎么办 联系人存储已停止运行怎么办 荣耀note8听筒声音小怎么办 红米4x内存不足怎么办 安卓电视内存小怎么办 红米手机运行内存不足怎么办 红米手机存储空间不足怎么办 华为手机储存空间不足怎么办 大麦机顶盒遥控器丢了怎么办 大麦盒子总自动加软件怎么办 小米手机玩王者荣耀卡怎么办 荣耀8青春版信号差怎么办 华为mate8电池不耐用怎么办 华为4x内存小怎么办 发现手机被用过怎么办 华为p8手机声音小怎么办 手机指纹解锁密码忘了怎么办 华为p10黑色掉漆怎么办 金立手机导航信号弱怎么办 手机导航时gps信号弱怎么办 三星手机导航gps信号弱怎么办 小米5导航信号弱怎么办 华为手机导航gps信号弱怎么办 手机屏玻璃裂了怎么办 oppo音量键坏了怎么办 魅蓝手机屏幕碎了怎么办 手机钢化膜边缘有气泡怎么办 手机贴钢化膜边缘有气泡怎么办 苹果手机钢化膜边缘有气泡怎么办 手机膜里的水泡怎么办 膜贴好了有气泡怎么办 后档玻璃膜气泡怎么办 贴膜里面有灰尘怎么办 贴膜边缘不粘怎么办 贴膜时候的气泡怎么办 贴手机膜起泡了怎么办