观察者模式

观察者模式:定义一种一对多的依赖关系,让多个观察者对象同时监控某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使他们能够自动更新自己。

这个模式比较绕。我尽量吧上面具体展示在代码位置进行注释,希望对你能有帮助。我也是饶了好久好了若干次关系图才理清。希望我的注解能对你理解这种模式有所帮助。

首先我们把主题与观察者接口定义:

public interface ISubject {
    public void registObserver(IObserve o);//注册
    public void logOutObserver(IObserve o);//注销
    public void notfiyObserver();//通知
}
public interface IObserve {
    public void update(String address,String weather, double humidity, double pm2_5);
}

观察者实现:

public class Person implements IObserve {
    private ISubject notice;
    private String name;
    public Person(String name) {
        this.name = name;
    }
    public void registObserver(ISubject notice){
        this.notice = notice;
        notice.registObserver(this);
    }
    public void removeObserver(ISubject notice){
        this.notice = notice;
        notice.logOutObserver(this);
    }
    @Override
    public void update(String address,String weather
            , double humidity, double pm2_5) {//获得通知后进行自动更新展示信息
        System.out.println("通知"+name+" "+address+"天气:"+weather+", 湿度:"
            +humidity+"%, pm2_5:"+pm2_5);
    }
}
public class Phone implements IObserve {
    private ISubject notice;
    private String name;
    public Phone(String name) {
        this.name = name;
    }
    public void registObserver(ISubject notice){
        this.notice = notice;
        notice.registObserver(this);
    }
    public void removeObserver(ISubject notice){
        this.notice = notice;
        notice.logOutObserver(this);
    }
    @Override
    public void update(String address,String weather,
            double humidity, double pm2_5) {//获得通知后进行自动更新展示信息
        System.out.println("通知"+name+" "+address+"天气:"+weather+
                ", 湿度:"+humidity+"%, pm2_5:"+pm2_5);
    }
}

主题实现:

public class Notice implements ISubject {//通知继承主题
    private String weather;
    private double humidity;
    private double pm2_5;
    private String address;
    //用来实现一对多依赖关系,也就是说一个主题对应多个通知观察者对象。
    Set<IObserve> io = new HashSet<IObserve>();
    public Notice(String address) {
        this.address = address;
    }
    @Override
    public void registObserver(IObserve o) {
        if(!io.contains(o))
            io.add(o);
    }

    @Override
    public void logOutObserver(IObserve o) {
        io.remove(o);
    }

    @Override
    public void notfiyObserver() {//通知订阅者
        for (IObserve iObserve : io) {
            iObserve.update( address,weather, humidity, pm2_5);
        }
    }
    public void notice( String weather,double humidity,double pm2_5){
        this.weather = weather;
        this.humidity = humidity;
        this.pm2_5 = pm2_5;

        notfiyObserver();//监控作用,当主题天气进行更新时进行通知观察者对象
    }
}

测试Client

public static void main(String[] args) {
        Notice is = new Notice("上海");
        Person PersonA = new Person("张三");
        Person PersonB = new Person("李四");
        Person PersonC = new Person("王五");
        Phone phone = new Phone("老大手机");
        PersonA.registObserver(is);
        PersonB.registObserver(is);
        PersonC.registObserver(is);
        phone.registObserver(is);
        is.notice("晴", 50, 35);
        Notice is1 = new Notice("北京");
        PersonA.registObserver(is1);
        PersonB.registObserver(is1);
        PersonB.removeObserver(is1);
        is1.notice("晴", 40, 35);
    }

输出结果:

通知老大手机 上海天气:晴, 湿度:50.0%, pm2_5:35.0
通知张三 上海天气:晴, 湿度:50.0%, pm2_5:35.0
通知李四 上海天气:晴, 湿度:50.0%, pm2_5:35.0
通知王五 上海天气:晴, 湿度:50.0%, pm2_5:35.0
通知张三 北京天气:晴, 湿度:40.0%, pm2_5:35.0

突然发现上面的 IObserve接口写的好烂,为什么会去规定通知内容格式,不符合设计模式的开闭原则,因此就临时进行了修改,为了记录就没有直接更改上面的代码就展示在下面了。主要还是参考了jdk提供的观察者模式文档。代码如下

接口:

public interface IObserve {
    public void update(ISubject notice);
}

实现:

public class Person implements IObserve {
    private ISubject notice;
    private String name;
    public Person(String name) {
        this.name = name;
    }
    public void registObserver(ISubject notice){
        this.notice = notice;
        notice.registObserver(this);
    }
    public void removeObserver(ISubject notice){
        this.notice = notice;
        notice.logOutObserver(this);
    }
    @Override
    public void update(ISubject o) {//获得通知后进行自动更新展示信息
        if(o instanceof Notice){
            Notice notice = (Notice) o;
            System.out.println("通知"+name+" "+notice.getAddress()+"天气:"+notice.getWeather()+
                ", 湿度:"+notice.getHumidity()+"%, pm2_5:"+notice.getPm2_5());
        }
    }
}

把传输格式由固定格式抽象化,因此不单单可以订阅不同位置的天气情况了,也可以订阅各种格式的类,只要进行相应的数据处理就ok。

那么接下来就看一下触发我灵感的JDK帮我们实现的观察者模式应用吧。

public class Notices extends Observable{
    private String weather;
    private double humidity;
    private double pm2_5;
    private String address;

    public Notices(String address) {
        this.address = address;
    }
    public void measurementsChanged() {
        setChanged();
        notifyObservers();
    }
    public void notice( String weather,double humidity,double pm2_5){
        this.weather = weather;
        this.humidity = humidity;
        this.pm2_5 = pm2_5;

        measurementsChanged();
    }
    public String getWeather() {
        return weather;
    }
    public double getHumidity() {
        return humidity;
    }
    public double getPm2_5() {
        return pm2_5;
    }
    public String getAddress() {
        return address;
    }
}
public class PersonC implements Observer{
    private Observable obs;
    private String name;
    public PersonC(String name) {
        this.name = name;
    }
    public void registObserver(Observable notice){
        this.obs = notice;
        notice.addObserver(this);
    }
    public void removeObserver(Observable notice){
        this.obs = notice;
        notice.deleteObserver(this);
    }
    @Override
    public void update(Observable arg0, Object arg1) {
        if(arg0 instanceof Notices){
            Notices o = (Notices) arg0;
            System.out.println("通知"+name+" "+o.getAddress()+"天气:"+o.getWeather()+", 湿度:"
            +o.getHumidity()+"%, pm2_5:"+o.getPm2_5());
        }
    }
}
    public static void main(String[] args) {
        Notices is = new Notices("shanghai");
        PersonC c = new PersonC("张三");
        c.registObserver(is);
        is.notice("晴", 50, 35);
    }

Observable 就是我们之前的主题类。相对来说JDK帮我们吧订阅删除通知帮助我们进行封装,我们不需要自己来管理只需要调用相应的接口就OK。 观察者类进本类似,调用也一样。

代码中用一个 setChanged方法来表示状态有改变,在发送改变前我们需要先使用setChanged()将其设置为true。 在 notifyObservers()之后自动调用 clearChanged() 恢复 changed 为false。所以不需要我们自己来重置。

Observable 中集合类是Vector 存储的,并且所有方法都是同步的,所以 Observable 都是线程安全的。可以用于多线程开发。
观察者模式消耗了我很长的时间,简单总结一下就是一对多依赖,多观察一,一改变,多进行自行改变。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值