设计模式--观察者模式初探和java Observable模式

小编 2026-07-15 阅读:1318 评论:0
初步认识观察者模式  观察者模式又称为发布/订阅(Publish/Subscribe)模式,因此...

初步认识观察者模式

  观察者模式又称为发布/订阅(Publish/Subscribe)模式,因此我们可以用报纸期刊的订阅来形象的说明:

    报社方负责出版报纸.

    你订阅了该报社的报纸,那么只要报社发布了新报纸,就会通知你,或发到你手上.

    如果你不想再读报纸,可以取消订阅,这样,报社发布了新报纸就不会再通知你.

  理解其实以上的概念,就可以理解观察者模式,观察者模式中有主题(Subject)和观察者(Observer),分别对应报社和订阅用户(你).观察者模式定义了对象之间的一对多的依赖关系,这样,当"一"的一方状态发生变化时,它所依赖的"多"的一方都会收到通知并且自动更新.如图:

      设计模式--观察者模式初探和java Observable模式

实现观察者模式

  这里以师生关系为例,老师和学生是一对多的关系,老师给学生布置作业,这个动作作为主题事件,每当老师布置一道题时,就要自动通知到所有的学生把该题记下来,然后再布置下一道题...

设计模式--观察者模式初探和java Observable模式

  这是一个并不标准的类图,主题接口和实现类中,一般需要有addObserver(),deleteObserver(),notifyObserver();用来注册删除观察者以及在主题状态发生变化时通知所有的观察者对象.

  接下来进行代码实现:

  Subject接口:

package com.wang.observer;//主题接口 interface Subject {     //添加观察者     void addObserver(Observer obj);     //移除观察者     void deleteObserver(Observer obj);     //当主题方法改变时,这个方法被调用,通知所有的观察者     void notifyObserver();}

  Oserver接口:

package com.wang.observer;interface Observer {    //当主题状态改变时,会将一个String类型字符传入该方法的参数,每个观察者都需要实现该方法    public void update(String info);}

Subject接口实现类TeacherSubject:

package com.wang.observer;import java.util.ArrayList;import java.util.List;public class TeacherSubject implements Subject {    //用来存放和记录观察者    private List<Observer> observers=new ArrayList<Observer>();    //记录状态的字符串    private String info;        @Override    public void addObserver(Observer obj) {        observers.add(obj);    }    @Override    public void deleteObserver(Observer obj) {        int i = observers.indexOf(obj);        if(i>=0){            observers.remove(obj);        }    }    @Override    public void notifyObserver() {        for(int i=0;i<observers.size();i++){            Observer o=(Observer)observers.get(i);            o.update(info);        }    }    //布置作业的方法,在方法最后,需要调用notifyObserver()方法,通知所有观察者更新状态    public void setHomework(String info){        this.info=info;        System.out.println("今天的作业是"+info);        this.notifyObserver();    }}

Observer接口实现类StudentObserver:

package com.wang.observer;public class StudentObserver implements Observer {    //保存一个Subject的引用,以后如果可以想取消订阅,有了这个引用会比较方便    private TeacherSubject t;    //学生的姓名,用来标识不同的学生对象    private String name;    //构造器用来注册观察者    public Student(String name,Teacher t) {        this.name=name;        this.t = t;        //每新建一个学生对象,默认添加到观察者的行列        t.addObserver(this);    }    @Override    public void update(String info) {        System.out.println(name+"得到作业:"+info);            }}

测试类TestObserver:

package com.wang.observer;public class TestObserver {    public static void main(String[] args) {                TeacherSubject teacher=new TeacherSubject();        StudentObserver zhangSan=new StudentObserver("张三", teacher);        StudentObserver LiSi=new StudentObserver("李四", teacher);        StudentObserver WangWu=new StudentObserver("王五", teacher);                teacher.setHomework("第二页第六题");        teacher.setHomework("第三页第七题");        teacher.setHomework("第五页第八题");    }}

打印结果:

今天的作业是第二页第六题
张三得到作业:第二页第六题
李四得到作业:第二页第六题
王五得到作业:第二页第六题
今天的作业是第三页第七题
张三得到作业:第三页第七题
李四得到作业:第三页第七题
王五得到作业:第三页第七题
今天的作业是第五页第八题
张三得到作业:第五页第八题
李四得到作业:第五页第八题
王五得到作业:第五页第八题

从打印结果看,每当老师布置作业的状态改变,就会通知每一个学生.以上就是一个简单的观察者模式的实现.

java内置的观察者模式:

  在java.util包中包含有基本的Observer接口和Observable抽象类.功能上和Subject接口和Observer接口类似.不过在使用上,就方便多了,因为许多功能比如说注册,删除,通知观察者的那些功能已经内置好了.

  使用javaAPI的观察者模式需要明白这么几件事情:

   如何使对象变为观察者?

    实现观察者接口(java.util.Observer),然后调用Observable对象的addObserver()方法.不想再当观察者时,调用deleteObserver()就可以了.

   被观察者(主题)如何发出通知?

    第一步:先调用setChanged()方法,标识状态已经改变的事实.

    第二步:调用notifyObservers()方法或者notifyObservers(Object arg),这就牵扯到推(push)和拉(pull)的方式传送数据.如果想用push的方式"推"数据给观察者,可以把数据当做数据对象传送给notifyObservers(Object arg)方法,其中的arg可以为任意对象,意思是你可以将任意对象传送给每一个观察者.如果调用不带参数的notifyObserver()方法,则意味着你要使用pull的方式去主题对象中"拉"来所需要的数据.

   观察者如何接收通知?

     观察者只需要实现一个update(Observable o,Object arg)方法,第一个参数o,是指定通知是由哪个主题下达的,第二个参数arg就是上面notifyObserver(Object arg)里传入的数据,如果不传该值,arg为null.

  下面使用java内置API实现上面我所写的老师和学生的例子:

被观察者TeacherSubject:

package com.wang.observer1;import java.util.Observable;public class Teacher extends Observable {        //布置作业的状态信息字符串    private String info;    public void setHomework(String info) {        this.info=info;        System.out.println("布置的作业是"+info);        setChanged();        notifyObservers();    }    public String getInfo() {        return info;    }}

观察者StudentObserver:

package com.wang.observer1;import java.util.Observable;import java.util.Observer;public class Student implements Observer{    private Observable ob;    private String name;    public Student(String name,Observable ob) {        this.ob = ob;        this.name=name;        ob.addObserver(this);    }    @Override    public void update(Observable o, Object arg) {        Teacher t=(Teacher)o;        System.out.println(name+"得到作业信息:"+t.getInfo());            }}

  测试代码和打印结果我就不再写了,和上面的例子是一样一样的,在这个例子中我使用的是"pull"的方式拉数据,在需要传递状态的TeacherSubject中定义了一个info字符串的get方法,在观察者对象中调用get方法得到所需数据,如果希望使用push的方式,只需要在TeacherSubject类的notifyOservers()方法中传入String类型的info字符串即可在update()方法中直接通过第二个参数获取到arg,即使前面传过来的info字符串.

 观察者模式的好处

  观察者模式提供了一种对象设计,让主题和观察者之间耦合度降得很低,为什么呢?关于观察者的一切,主题只知道观察者实现了Observer接口,并不需要观察者具体的类是谁,做了什么或者其他细节.

  这样的话,由于松耦合,改变主题或者观察者其中一方,并不会影响另一方,只要他们之间的接口仍被遵守,就可以自由地改变它.

  降低对象之间的耦合度,也是面设对象设计的一个很重要的原则.  

 

版权声明

本文仅代表作者观点,不代表百度立场。
本文系作者授权百度百家发表,未经许可,不得转载。

热门文章
  • Sequential Monte Carlo Methods (SMC) 序列蒙特卡洛/粒子滤波/Bootstrap Filtering

    Sequential Monte Carlo Methods (SMC) 序列蒙特卡洛/粒子滤波/Bootstrap Filtering
    Problem Statement 我们考虑一个具有马尔可夫性质、非线性、非高斯的状态空间模型(State Space Model):对于一个时间序列上的观测结果{yt,t∈N}\\{ y_t , t \\in N \\}{yt​,t∈N},我们认为每个观测结果yty_tyt​的生成依赖于一个无法直接观察的隐变量xt∈{xt,t∈N}x_t \\in \\{x_t , t \\in N \\}xt​∈{xt​,t∈N},即:p(...
  • 机房智能化温湿度解决方式之POE供电以太网温湿度传感器

    机房智能化温湿度解决方式之POE供电以太网温湿度传感器
    机房智能化温湿度解决方式之POE供电以太网温湿度传感器 北京盈创力和电子科技有限公司 智能型TCP网口温湿度记录仪 北京IP网络温湿度记录仪厂家,北京盈创力和 北京智能型TCP网口温湿度记录仪IP网络温湿度记录仪是一种新型的基于TCP/IP协议双绞线以太网标准温湿度采集模块,利用它可以实现现场温度值、相对湿度值的采集,同时利用其自身的RJ45通信接口可以方便地和机房监控主机或交换机集线器进行联网。 工作于-40℃~85℃工业级带...
  • Hive 系统函数及示例

    Hive 系统函数及示例
    查看所有系统函数 show functions; 函数分类 内置函数【系统函数】 数学函数: floor、round、ceil、cos、log2等 字符串函数: length、reverse、trim、lower、get_json_object、repeat等 收集函数: size 转换函数: cast 日期函数: year、month、datediff、date、date_add等 条件函数: coalesce、case…w...
  • CSRF的原理和防范措施

    CSRF的原理和防范措施
    a)攻击原理:i.用户C访问正常网站A时进行登录,浏览器保存A的cookieii.用户C再访问攻击网站B,网站B上有某个隐藏的链接或者图片标签会自动请求网站A的URL地址,例如表单提交,传指定的参数iii.而攻击网站B在访问网站A的时候,浏览器会自动带上网站A的cookieiv.所以网站A在接收到请求之后可判断当前用户是登录状态,所以...
  • HTTP状态保持的原理

    HTTP状态保持的原理
    a)在用户登录之后,浏览器返回响应的时候会在响应中添加上cookieb)浏览器接收到cookie之后会自动保存c)当用户再次请求同一服务器中的其他网页的时候,浏览器会自动带上之前保存的cookied)服务接收到请求之后可以请 request 对象中取到cookie 判断当前用户是否登录  Http是无状态的,就是连接时数据互通,关闭后...
标签列表